├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── README_CN.md ├── bundle.css ├── data.json ├── dist └── vue-trees.js ├── package.json ├── rollup.config.js └── src ├── components ├── default.css ├── fold.css ├── index.vue └── transition.js ├── images ├── afterMod.png └── beforeMod.jpg └── vue-trees.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=vue 2 | *.css linguist-language=vue 3 | *.html linguist-language=vue -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 码上码下 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-trees 2 | a tree UI base on vue 2.X 3 | 4 | ### install 5 | ``` 6 | npm install vue-trees --save 7 | or 8 | cnpm i vue-trees -S 9 | ``` 10 | 11 | ### Quick start 12 | ``` 13 | import Vue from 'vue' 14 | import vueTrees from 'vue-trees' 15 | 16 | Vue.use(vueTrees) 17 | ``` 18 | 19 | ## API DOC ([中文文档](https://github.com/wyr1227/vue-trees/blob/master/README_CN.md)) 20 | 21 | ### data Property 22 | The data property does not support properties inherited from the prototype chain (if you can use to consider whether the under-complex, it is recommended to check the code) 23 | 24 | | Param | Description | Types | Editable | Default value | 25 | |---------- |-------- |---------- |---------- |---------- | 26 | |title     | Node name | String | - | — | 27 | |expanded | Whether the node is expanded | Boolean | Y | false | 28 | |checked | Node check box is selected | Boolean | Y | false | 29 | 30 | ### tree Property 31 | | Param | Description | Types | Editable | Default value | 32 | |---------- |-------- |---------- |---------- |---------- | 33 | |type     | Tree style | String | Y | default | 34 | |canCheck     | Node can choose | Boolean | Y | false | 35 | |draggable | Whether the node can drag | Boolean | Y | false | 36 | |dragAndExpanded | Whether to expand after dragging | Boolean | Y | true | 37 | |control | Add or delete trees | Boolean | Y | false | 38 | |isSolid | Whether it is solid | Boolean | Y | false | 39 | |banCheck | Prohibition of choice | Boolean | Y | false | 40 | |bgColor | Background color (default type is useless) | String | Y | #fff | 41 | |fontColor | Font color (default type is useless) | String | Y | #000 | 42 | 43 | ### node event 44 | | Param | Description | Types | Editable | Arguments | 45 | |---------- |-------- |---------- |---------- |---------- | 46 | |beforeAddNode | Increase the node before the trigger event (return 'no' means no new) | Function | Y | 1:Parent node | 47 | |afterAddNode | Increase the node after the trigger event | Function | Y | 1:Add node,2:Parent node | 48 | |beforeDelNode     | Delete the node before the trigger event (return 'no' means do not delete) | Function | Y | 1:Current node | 49 | |afterAddNode | Event triggered after node deletion | Function | Y | 1:Current node | 50 | |beforeDragNode     | Drag the node before the trigger event (return 'no' means do not drag) | Function | Y | 1:Drag node,2:Target node | 51 | |afterDragNode | Drag the node after the trigger event | Function | Y | 1:Drag node, 2:Target node | 52 | 53 | ### Demo 54 | ``` 55 | 62 | 63 | 132 | 133 | 158 | 159 | ``` 160 | ### Example of effect 161 | #### If you can not see my picture please go my [github](https://github.com/wyr1227/vue-trees) 162 | #### If you find any problems during use please feel free to Issues 163 | 164 | 165 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # vue-trees 2 | 一个基于Vue2.x的树形控件 3 | 4 | ### 安装 5 | ``` 6 | npm install vue-trees --save 7 | 或者 8 | cnpm i vue-trees -S 9 | ``` 10 | 11 | ### 快速开始 12 | ``` 13 | import Vue from 'vue' 14 | import vueTrees from 'vue-trees' 15 | 16 | Vue.use(vueTrees) 17 | ``` 18 | 19 | ## API 文档 ([英文文档](https://github.com/wyr1227/vue-trees/blob/master/README.md)) 20 | 21 | ### data 属性 22 | data属性不支持从原型链上继承的属性(如果用到可以考虑下是否过于复杂,建议检查下代码) 23 | 24 | | 参数 | 说明 | 类型 | 可编辑 | 默认值 | 25 | |---------- |-------- |---------- |---------- |---------- | 26 | |title     | 节点名称 | String | - | — | 27 | |expanded | 节点是否展开 | Boolean | Y | false | 28 | |checked | 节点复选框是否选中 | Boolean | Y | false | 29 | 30 | ### tree 属性 31 | | 参数 | 说明 | 类型 | 可编辑 | 默认值 | 32 | |---------- |-------- |---------- |---------- |---------- | 33 | |type     | 树状图类型 | String | Y | default | 34 | |canCheck     | 节点是否可以选择 | Boolean | Y | false | 35 | |draggable | 节点是否可拖拽 | Boolean | Y | false | 36 | |dragAndExpanded | 拖拽后是否展开 | Boolean | Y | true | 37 | |control | 对树进行增删 | Boolean | Y | false | 38 | |isSolid | 是否是实线 | Boolean | Y | false | 39 | |banCheck | 禁止选择 | Boolean | Y | false | 40 | |bgColor | 背景颜色(default类型下无用) | String | Y | #fff | 41 | |fontColor | 字体颜色(default类型下无用) | String | Y | #000 | 42 | 43 | ### node 事件 44 | | 参数 | 说明 | 类型 | 可编辑 | 参数 | 45 | |---------- |-------- |---------- |---------- |---------- | 46 | |beforeAddNode | 增加节点前触发事件(返回'no'表示不新增) | Function | Y | 1:父节点 | 47 | |afterAddNode | 增加节点后触发事件 | Function | Y | 1:新增节点,2:父节点 | 48 | |beforeDelNode     | 删除节点前触发事件(返回'no'表示不删除) | Function | Y | 1:当前节点 | 49 | |afterAddNode | 删除节点后触发事件 | Function | Y | 1:当前节点 | 50 | |beforeDragNode     | 拖拽节点前触发事件(返回'no'表示不拖拽) | Function | Y | 1:拖拽节点,2:目标节点 | 51 | |afterDragNode | 拖拽节点后触发事件 | Function | Y | 1:拖拽节点, 2:目标节点 | 52 | 53 | ### 实例 54 | ``` 55 | 62 | 63 | 132 | 133 | 158 | 159 | ``` 160 | ### 效果实例 161 | #### 如果你看不见我的图片请去 [github](https://github.com/wyr1227/vue-trees) 162 | #### 如果在使用过程中发现任何问题欢迎随时Issues 163 | 164 | 165 | -------------------------------------------------------------------------------- /bundle.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /*# sourceMappingURL=index.vue.map */ 4 | -------------------------------------------------------------------------------- /data.json: -------------------------------------------------------------------------------- 1 | [{"title": "第一个", 2 | "expanded": true, 3 | "children": [{ 4 | "title": "node 1-1", 5 | "expanded": true, 6 | "children": [{ 7 | "title": "node 1-1-1" 8 | }, { 9 | "title": "node 1-1-2" 10 | }, { 11 | "title": "node 1-1-3" 12 | }] 13 | }] 14 | }, 15 | { 16 | "title": "第二个" 17 | }] -------------------------------------------------------------------------------- /dist/vue-trees.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 3 | typeof define === 'function' && define.amd ? define(factory) : 4 | (global['vue-trees'] = factory()); 5 | }(this, (function () { 'use strict'; 6 | 7 | function __$$styleInject(css, ref) { 8 | if ( ref === void 0 ) ref = {}; 9 | var insertAt = ref.insertAt; 10 | 11 | if (!css || typeof document === 'undefined') { return; } 12 | 13 | var head = document.head || document.getElementsByTagName('head')[0]; 14 | var style = document.createElement('style'); 15 | style.type = 'text/css'; 16 | 17 | if (insertAt === 'top') { 18 | if (head.firstChild) { 19 | head.insertBefore(style, head.firstChild); 20 | } else { 21 | head.appendChild(style); 22 | } 23 | } else { 24 | head.appendChild(style); 25 | } 26 | 27 | if (style.styleSheet) { 28 | style.styleSheet.cssText = css; 29 | } else { 30 | style.appendChild(document.createTextNode(css)); 31 | } 32 | } 33 | 34 | var css = ".wyr-trees-dfault ul,.wyr-trees-dfault li {\n list-style-type:none;\n text-align:left;\n}\n\n.wyr-trees-dfault .tree-open {\n line-height: 13px;\n}\n\n.wyr-trees-dfault .tree-open:after {\n content: \"\\2013\";\n font-style: normal;\n}\n\n.wyr-trees-dfault .tree-close:after {\n content: \"+\";\n font-style: normal;\n}\n\n.wyr-trees-dfault .tree-open,\n.wyr-trees-dfault .tree-close {\n display: inline-block;\n width:14px;\n height:14px;\n text-align: center;\n line-height: 13px;\n border: 1px solid #888888;\n border-radius: 2px;\n background: #FFFFFF;\n}\n\n.wyr-trees-dfault .tree-open:after {\n content: \"\\2013\";\n font-style: normal;\n}\n.wyr-trees-dfault .tree-add {\n padding: 5px 10px;\n background-color: #00FF99;\n color: white;\n font-weight: bold;\n cursor: pointer;\n}\n.wyr-trees-dfault .tree-del {\n padding: 5px 10px;\n background-color: #990033;\n color: white;\n font-weight: bold;\n cursor: pointer;\n}\n.wyr-trees-dfault .tree-exit {\n padding: 5px 10px;\n background-color: #CCFF66;\n color: white;\n font-weight: bold;\n cursor: pointer;\n}\n.wyr-trees-dfault .tree-open {\n line-height: 13px;\n}\n\n.wyr-trees-dfault .box-halfchecked {\n background-color: #888888;\n}\n.wyr-trees-dfault .box-halfchecked:after {\n content:\"\\2713\";\n display:block;\n position:absolute;\n z-index:1;\n width:100%;\n text-align:center;\n color: #FFFFFF;\n}\n.wyr-trees-dfault .inputCheck.wyr-trees-dfault:after {\n content:\"\\2713\";\n display:block;\n position:absolute;\n z-index:1;\n width:100%;\n text-align:center;\n}\n.wyr-trees-dfault .check{\n display:block;\n position:absolute;\n font-size:14px;\n width:16px;\n height:16px;\n left:-5px;\n top:-4px;\n border:1px solid #000000;\n opacity:0;\n cursor:pointer;\n -ms-filter:\"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)\";\n filter:alpha(opacity=0);\n z-index:2;\n}\n.wyr-trees-dfault .chkDisabled {\n background-color: #F5F5F5;\n opacity: 1;\n cursor: not-allowed;\n }\n\n .wyr-trees-dfault li span:hover {\n background-color: #dddddde3\n }\n .wyr-trees-dfault ul,.wyr-trees-dfault li {\n list-style-type:none;\n text-align:left;\n }\n .wyr-trees-dfault li {\n margin: 0;\n padding: 5px 5px 5px 15px;\n position: relative;\n list-style: none;\n }\n .wyr-trees-dfault li:after,\n .wyr-trees-dfault li:before {\n content: '';\n left: -8px;\n position: absolute;\n right: auto;\n border-width: 1px\n }\n .wyr-trees-dfault .is-dashed:before {\n border-left: 1px dashed #999;\n bottom: 50px;\n height: 100%;\n top: -8px;\n width: 1px;\n }\n .wyr-trees-dfault .is-solid:before {\n border-left: 1px solid #999;\n bottom: 50px;\n height: 100%;\n top: -8px;\n width: 1px;\n }\n .wyr-trees-dfault .is-dashed:after {\n border-top: 1px dashed #999;\n height: 20px;\n top: 17px;\n width: 28px\n }\n .wyr-trees-dfault .is-solid:after {\n border-top: 1px solid #999;\n height: 20px;\n top: 17px;\n width: 28px\n }\n .wyr-trees-dfault li:last-child::before {\n height: 26px\n }\n .wyr-trees-dfault>li.first-node:before {\n top: 17px;\n }\n .wyr-trees-dfault>li.first-node.only-node::before {\n border-left: none;\n }\n .wyr-trees-dfault > ul {\n padding-left: 0\n }\n .wyr-trees-dfault {\n padding-left: 17px;\n padding-top: 10px;\n }\n .wyr-trees-dfault li.leaf {\n padding-left: 15px;\n }\n .wyr-trees-dfault li.is-solid:after {\n content: '';\n left: -7px;\n position: absolute;\n right: auto;\n border-width: 1px;\n border-top: 1px solid #999;\n height: 20px;\n top: 17px;\n width: 25px;\n }\n .wyr-trees-dfault li.is-dashed:after {\n content: '';\n left: -7px;\n position: absolute;\n right: auto;\n border-width: 1px;\n border-top: 1px dashed #999;\n height: 20px;\n top: 17px;\n width: 25px;\n }\n .wyr-trees-dfault .tree-node-leaf {\n background-color: #FFFFFF;\n padding-left: 2px;\n position: relative;\n z-index: 3;\n }\n .wyr-trees-dfault .node-title {\n padding: 3px 3px;\n border-radius: 3px;\n cursor: pointer;\n margin: 0 2px;\n }\n .wyr-trees-dfault>li.first-node:before {\n top: 17px;\n }\n .wyr-trees-dfault>li.first-node.only-node::before {\n border-left: none;\n }\n .wyr-trees-dfault>li.first-node.only-node::before {\n border-left: none;\n }\n .wyr-trees-dfault>li.only-node:after {\n border-top: none;\n }\n\n .wyr-trees-dfault .inputCheck {\n display:inline-block;\n position:relative;\n width:14px;\n height:14px;\n border:1px solid #888888;\n border-radius:2px;\n top:4px;\n text-align:center;\n font-size:14px;\n line-height:14px;\n }\n .wyr-trees-dfault .inputCheck.notAllNodes:before {\n content:\"\\2713\";\n display:block;\n position:absolute;\n width:100%;\n height:100%;\n background-color:#888888;\n z-index:1;\n color:#ffffff;\n }\n .wyr-trees-dfault .inputCheck.box-checked:after {\n content:\"\\2713\";\n display:block;\n position:absolute;\n z-index:1;\n width:100%;\n text-align:center;\n }"; 35 | __$$styleInject(css); 36 | 37 | var css$2 = ".wyr-trees-fold {\n padding-left: 0px;\n padding-top: 0px;\n}\n.wyr-trees-fold ul,.wyr-trees-fold li {\n list-style-type:none;\n text-align:left;\n}\n.wyr-trees-fold .tree-node-leaf {\n background-color: white;\n padding: 10px 2px;\n /* border-top: 1px solid #ebeef5; */\n border-bottom: 1px solid #ebeef5;\n}\n.wyr-trees-fold .tree-arrow-right {\n display: inline-block; \n border-right: 3px solid; border-bottom: 3px solid; \n width: 8px; height: 8px; \n transform: rotate(-45deg);\n transition: transform .3s;\n}\n.wyr-trees-fold .tree-arrow-down {\n display: inline-block; \n border-right: 3px solid; border-bottom: 3px solid; \n width: 8px; height: 8px; \n transform: rotate(45deg);\n transition: transform .3s;\n}\n.wyr-trees-fold .tree-down {\n height: 100%;\n padding: 0 20px;\n float: right;\n}\n\n/* .wyr-trees-fold .node-title {\n padding-left: 10px;\n} */"; 38 | __$$styleInject(css$2); 39 | 40 | var elTransition = '0.3s height ease-in-out, 0.3s padding-top ease-in-out, 0.3s padding-bottom ease-in-out'; 41 | 42 | function beforeEnter(el) { 43 | el.style.transition = elTransition; 44 | if (!el.dataset) el.dataset = {}; 45 | 46 | el.dataset.oldPaddingTop = el.style.paddingTop; 47 | el.dataset.oldPaddingBottom = el.style.paddingBottom; 48 | 49 | el.style.height = 0; 50 | el.style.paddingTop = 0; 51 | el.style.paddingBottom = 0; 52 | } 53 | function enter(el) { 54 | el.dataset.oldOverflow = el.style.overflow; 55 | if (el.scrollHeight !== 0) { 56 | el.style.height = el.scrollHeight + 'px'; 57 | el.style.paddingTop = el.dataset.oldPaddingTop; 58 | el.style.paddingBottom = el.dataset.oldPaddingBottom; 59 | } else { 60 | el.style.height = ''; 61 | el.style.paddingTop = el.dataset.oldPaddingTop; 62 | el.style.paddingBottom = el.dataset.oldPaddingBottom; 63 | } 64 | 65 | el.style.overflow = 'hidden'; 66 | } 67 | function afterEnter(el) { 68 | el.style.transition = ''; 69 | el.style.height = ''; 70 | el.style.overflow = el.dataset.oldOverflow; 71 | } 72 | 73 | function beforeLeave(el) { 74 | if (!el.dataset) el.dataset = {}; 75 | el.dataset.oldPaddingTop = el.style.paddingTop; 76 | el.dataset.oldPaddingBottom = el.style.paddingBottom; 77 | el.dataset.oldOverflow = el.style.overflow; 78 | 79 | el.style.height = el.scrollHeight + 'px'; 80 | el.style.overflow = 'hidden'; 81 | } 82 | 83 | function leave(el) { 84 | if (el.scrollHeight !== 0) { 85 | el.style.transition = elTransition; 86 | el.style.height = 0; 87 | el.style.paddingTop = 0; 88 | el.style.paddingBottom = 0; 89 | } 90 | } 91 | 92 | function afterLeave(el) { 93 | el.style.transition = ''; 94 | el.style.height = ''; 95 | el.style.overflow = el.dataset.oldOverflow; 96 | el.style.paddingTop = el.dataset.oldPaddingTop; 97 | el.style.paddingBottom = el.dataset.oldPaddingBottom; 98 | } 99 | 100 | var transition = { 101 | methods: { 102 | beforeEnter: beforeEnter, 103 | enter: enter, 104 | afterEnter: afterEnter, 105 | beforeLeave: beforeLeave, 106 | leave: leave, 107 | afterLeave: afterLeave 108 | } 109 | }; 110 | 111 | var Trees = { render: function render() { 112 | var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('div', [_vm.type === 'fold' ? _c('ul', { staticClass: "wyr-trees-fold" }, _vm._l(_vm.data, function (item, index) { 113 | return _c('li', { class: { 'leaf': _vm.haveLeaf(item), 'first-node': !_vm.parent && index === 0, 'only-node': !_vm.parent && _vm.data.length === 1 }, on: { "drop": function drop($event) { 114 | _vm.drop(item, $event); 115 | }, "dragover": function dragover($event) { 116 | _vm.dragover($event); 117 | } } }, [_c('div', { staticClass: "tree-node-leaf", style: { 'background-color': _vm.bgColor, 'color': _vm.fontColor }, attrs: { "draggable": _vm.draggable }, on: { "dragstart": function dragstart($event) { 118 | _vm.drag(item, $event); 119 | } } }, [_c('span', { staticClass: "tree-down", on: { "click": function click($event) { 120 | _vm.expandTree(item, $event); 121 | } } }, [_c('span', { class: item.children && item.children.length > 0 ? item.expanded ? 'tree-arrow-down' : 'tree-arrow-right' : '' })]), _vm._v(" "), !_vm.control ? _c('span', { staticClass: "node-title", style: { 'padding-left': _vm.times * 17 + 'px' } }, [_vm._v(_vm._s(item.title))]) : _vm._e(), _vm._v(" "), _vm.control ? _c('input', { directives: [{ name: "model", rawName: "v-model", value: item.title, expression: "item.title" }], staticClass: "node-title", style: { 'margin-left': _vm.times * 17 + 'px' }, attrs: { "type": "text" }, domProps: { "value": item.title }, on: { "input": function input($event) { 122 | if ($event.target.composing) { 123 | return; 124 | }_vm.$set(item, "title", $event.target.value); 125 | } } }) : _vm._e(), _vm._v(" "), _vm.control ? _c('span', [_c('span', { staticClass: "tree-add", on: { "click": function click($event) { 126 | _vm.addNode(item); 127 | } } }, [_vm._v("Add")]), _vm._v(" "), _c('span', { staticClass: "tree-del", on: { "click": function click($event) { 128 | _vm.delNode(item); 129 | } } }, [_vm._v("Del")])]) : _vm._e()]), _vm._v(" "), _c('transition', { on: { "before-enter": _vm.beforeEnter, "enter": _vm.enter, "after-enter": _vm.afterEnter, "before-leave": _vm.beforeLeave, "leave": _vm.leave, "after-leave": _vm.afterLeave } }, [!_vm.haveLeaf(item) ? _c('Trees', { directives: [{ name: "show", rawName: "v-show", value: item.expanded, expression: "item.expanded" }], attrs: { "type": _vm.type, "afterAddNode": _vm.afterAddNode, "beforeAddNode": _vm.beforeAddNode, "beforeDelNode": _vm.beforeDelNode, "afterDelNode": _vm.afterDelNode, "beforeDragNode": _vm.beforeDragNode, "afterDragNode": _vm.afterDragNode, "times": _vm.times + 1, "fontColor": _vm.fontColor, "bgColor": _vm.bgColor, "data": item.children, "parent": item, "canCheck": _vm.canCheck, "draggable": _vm.draggable, "control": _vm.control } }) : _vm._e()], 1)], 1); 130 | })) : _vm._e(), _vm._v(" "), _vm.type === 'default' ? _c('ul', { staticClass: "wyr-trees-dfault" }, _vm._l(_vm.data, function (item, index) { 131 | return _c('li', { class: { 'is-solid': _vm.isSolid, 'is-dashed': !_vm.isSolid, 'leaf': _vm.haveLeaf(item), 'first-node': !_vm.parent && index === 0, 'only-node': !_vm.parent && _vm.data.length === 1 }, on: { "drop": function drop($event) { 132 | _vm.drop(item, $event); 133 | }, "dragover": function dragover($event) { 134 | _vm.dragover($event); 135 | } } }, [_c('div', { staticClass: "tree-node-leaf", style: { 'background-color': _vm.bgColor, 'color': _vm.fontColor }, attrs: { "draggable": _vm.draggable }, on: { "dragstart": function dragstart($event) { 136 | _vm.drag(item, $event); 137 | } } }, [!!item.children && item.children && item.children.length > 0 ? _c('span', { class: item.expanded ? 'tree-open' : 'tree-close', on: { "click": function click($event) { 138 | _vm.expandTree(item); 139 | } } }) : _vm._e(), _vm._v(" "), _vm.canCheck && !item.nocheck ? _c('span', { class: [item.checked ? 'box-checked' : 'box-unchecked', 'inputCheck'] }, [_vm.canCheck ? _c('input', { directives: [{ name: "model", rawName: "v-model", value: item.checked, expression: "item.checked" }], class: ['check', item.banCheck ? 'chkDisabled' : ''], attrs: { "disabled": item.banCheck, "type": "checkbox" }, domProps: { "checked": Array.isArray(item.checked) ? _vm._i(item.checked, null) > -1 : item.checked }, on: { "change": function change($event) { 140 | var $$a = item.checked, 141 | $$el = $event.target, 142 | $$c = $$el.checked ? true : false;if (Array.isArray($$a)) { 143 | var $$v = null, 144 | $$i = _vm._i($$a, $$v);if ($$el.checked) { 145 | $$i < 0 && (item.checked = $$a.concat([$$v])); 146 | } else { 147 | $$i > -1 && (item.checked = $$a.slice(0, $$i).concat($$a.slice($$i + 1))); 148 | } 149 | } else { 150 | _vm.$set(item, "checked", $$c); 151 | } 152 | } } }) : _vm._e()]) : _vm._e(), _vm._v(" "), !_vm.control ? _c('span', { staticClass: "node-title", on: { "click": function click($event) { 153 | _vm.nodeCheck(item, _vm.check); 154 | } } }, [_vm._v(_vm._s(item.title))]) : _vm._e(), _vm._v(" "), _vm.control ? _c('input', { directives: [{ name: "model", rawName: "v-model", value: item.title, expression: "item.title" }], staticClass: "node-title", attrs: { "type": "text" }, domProps: { "value": item.title }, on: { "input": function input($event) { 155 | if ($event.target.composing) { 156 | return; 157 | }_vm.$set(item, "title", $event.target.value); 158 | } } }) : _vm._e(), _vm._v(" "), _vm.control ? _c('span', [_c('span', { staticClass: "tree-add", on: { "click": function click($event) { 159 | _vm.addNode(item); 160 | } } }, [_vm._v("Add")]), _vm._v(" "), _c('span', { staticClass: "tree-del", on: { "click": function click($event) { 161 | _vm.delNode(item); 162 | } } }, [_vm._v("Del")])]) : _vm._e()]), _vm._v(" "), _c('transition', { on: { "before-enter": _vm.beforeEnter, "enter": _vm.enter, "after-enter": _vm.afterEnter, "before-leave": _vm.beforeLeave, "leave": _vm.leave, "after-leave": _vm.afterLeave } }, [!_vm.haveLeaf(item) ? _c('Trees', { directives: [{ name: "show", rawName: "v-show", value: item.expanded, expression: "item.expanded" }], attrs: { "isSolid": _vm.isSolid, "type": _vm.type, "afterAddNode": _vm.afterAddNode, "beforeAddNode": _vm.beforeAddNode, "beforeDelNode": _vm.beforeDelNode, "afterDelNode": _vm.afterDelNode, "beforeDragNode": _vm.beforeDragNode, "afterDragNode": _vm.afterDragNode, "fontColor": _vm.fontColor, "bgColor": _vm.bgColor, "data": item.children, "parent": item, "canCheck": _vm.canCheck, "draggable": _vm.draggable, "control": _vm.control } }) : _vm._e()], 1)], 1); 163 | })) : _vm._e()]); 164 | }, staticRenderFns: [], 165 | name: 'Trees', 166 | mixins: [transition], 167 | props: { 168 | data: { 169 | type: Array, 170 | default: function _default() { 171 | return []; 172 | } 173 | }, 174 | parent: { 175 | type: Object, 176 | default: function _default() { 177 | return null; 178 | } 179 | }, 180 | line: { 181 | type: Boolean, 182 | default: true 183 | }, 184 | control: { 185 | type: Boolean, 186 | default: false 187 | }, 188 | canCheck: { 189 | type: Boolean, 190 | default: true 191 | }, 192 | draggable: { 193 | type: Boolean, 194 | default: true 195 | }, 196 | dragAndExpanded: { 197 | type: Boolean, 198 | default: true 199 | }, 200 | type: { 201 | type: String, 202 | default: function _default() { 203 | return 'default'; 204 | } 205 | }, 206 | bgColor: { 207 | type: String, 208 | default: function _default() { 209 | return 'white'; 210 | } 211 | }, 212 | fontColor: { 213 | type: String, 214 | default: function _default() { 215 | return 'black'; 216 | } 217 | }, 218 | afterAddNode: { 219 | type: Function, 220 | default: function _default() { 221 | return null; 222 | } 223 | }, 224 | beforeAddNode: { 225 | type: Function, 226 | default: function _default() { 227 | return null; 228 | } 229 | }, 230 | beforeDelNode: { 231 | type: Function, 232 | default: function _default() { 233 | return null; 234 | } 235 | }, 236 | afterDelNode: { 237 | type: Function, 238 | default: function _default() { 239 | return null; 240 | } 241 | }, 242 | beforeDragNode: { 243 | type: Function, 244 | default: function _default() { 245 | return null; 246 | } 247 | }, 248 | afterDragNode: { 249 | type: Function, 250 | default: function _default() { 251 | return null; 252 | } 253 | }, 254 | isSolid: { 255 | type: Boolean, 256 | default: false 257 | }, 258 | times: { 259 | type: Number, 260 | default: 1 261 | } 262 | }, 263 | data: function data() { 264 | return { 265 | num: 0, 266 | check: true 267 | }; 268 | }, 269 | mounted: function mounted() { 270 | this.initParent(); 271 | }, 272 | 273 | watch: { 274 | data: function data() { 275 | this.initParent(); 276 | } 277 | }, 278 | methods: { 279 | guid: function guid() { 280 | return this.num++; 281 | }, 282 | haveLeaf: function haveLeaf(node) { 283 | return !(node.children && node.children.length) && node.parent; 284 | }, 285 | drag: function drag(node, ev) { 286 | var guid = this.guid(); 287 | this.setDragNode(guid, node); 288 | ev.dataTransfer.setData('guid', guid); 289 | }, 290 | dragover: function dragover(ev) { 291 | ev.preventDefault(); 292 | ev.stopPropagation(); 293 | }, 294 | drop: function drop(node, ev) { 295 | ev.preventDefault(); 296 | ev.stopPropagation(); 297 | var guid = ev.dataTransfer.getData('guid'); 298 | var drag = this.getDragNode(guid); 299 | var isNo = this.beforeDragNode(drag, node); 300 | if (isNo !== 'no') { 301 | if (ev.target.className == 'tree-node-leaf' || ev.target.className == 'check' || ev.target.className == 'tree-close' || ev.target.className == 'tree-add' || ev.target.className == 'tree-del') return false; 302 | if (!node.title || drag.title == ev.target.innerHTML) return false; 303 | if (drag.parent === node || drag.parent === null) return false; 304 | if (this.isParent(drag, node)) return false; 305 | var dragParent = drag.parent.children; 306 | if (node.children && node.children.indexOf(drag) === -1) { 307 | node.children.push(drag); 308 | dragParent.splice(dragParent.indexOf(drag), 1); 309 | } else { 310 | this.$set(node, 'children', [drag]); 311 | dragParent.splice(dragParent.indexOf(drag), 1); 312 | } 313 | this.$set(node, 'expanded', this.dragAndExpanded); 314 | this.beforeDragNode(drag, node); 315 | } 316 | }, 317 | setDragNode: function setDragNode(guid, node) { 318 | window['drageTarget'] = {}; 319 | window['drageTarget'][guid] = node; 320 | }, 321 | getDragNode: function getDragNode(guid) { 322 | return window['drageTarget'][guid]; 323 | }, 324 | initParent: function initParent() { 325 | var _iteratorNormalCompletion = true; 326 | var _didIteratorError = false; 327 | var _iteratorError = undefined; 328 | 329 | try { 330 | for (var _iterator = this.data[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 331 | var node = _step.value; 332 | 333 | this.$set(node, 'parent', this.parent); 334 | } 335 | } catch (err) { 336 | _didIteratorError = true; 337 | _iteratorError = err; 338 | } finally { 339 | try { 340 | if (!_iteratorNormalCompletion && _iterator.return) { 341 | _iterator.return(); 342 | } 343 | } finally { 344 | if (_didIteratorError) { 345 | throw _iteratorError; 346 | } 347 | } 348 | } 349 | }, 350 | isParent: function isParent(parent, node) { 351 | if (parent.hasOwnProperty('children')) { 352 | var _iteratorNormalCompletion2 = true; 353 | var _didIteratorError2 = false; 354 | var _iteratorError2 = undefined; 355 | 356 | try { 357 | for (var _iterator2 = parent.children[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { 358 | var chilren = _step2.value; 359 | 360 | if (chilren === node) return true; 361 | if (chilren.children) return this.isParent(chilren, node); 362 | } 363 | } catch (err) { 364 | _didIteratorError2 = true; 365 | _iteratorError2 = err; 366 | } finally { 367 | try { 368 | if (!_iteratorNormalCompletion2 && _iterator2.return) { 369 | _iterator2.return(); 370 | } 371 | } finally { 372 | if (_didIteratorError2) { 373 | throw _iteratorError2; 374 | } 375 | } 376 | } 377 | 378 | return false; 379 | } 380 | }, 381 | expandTree: function expandTree(node, ev) { 382 | this.$set(node, 'expanded', !node.expanded); 383 | if (this.type === 'fold') { 384 | if (ev.target.children[0]) { 385 | var arrow = ev.target.children[0].className; 386 | if (arrow === 'tree-arrow-right') { 387 | arrow = 'tree-arrow-down'; 388 | } else { 389 | arrow = 'tree-arrow-right'; 390 | } 391 | } else { 392 | var _arrow = ev.target.className; 393 | if (_arrow === 'tree-arrow-right') { 394 | _arrow = 'tree-arrow-down'; 395 | } else { 396 | _arrow = 'tree-arrow-right'; 397 | } 398 | } 399 | } 400 | }, 401 | addNode: function addNode(node) { 402 | var isNo = this.beforeAddNode(node); 403 | if (isNo !== 'no') { 404 | var newNode = { 405 | title: 'newNode', 406 | expanded: true 407 | }; 408 | if (node.hasOwnProperty('children')) { 409 | node.children.push(newNode); 410 | } else { 411 | this.$set(node, "children", [newNode]); 412 | } 413 | this.afterAddNode(newNode, node); 414 | } 415 | }, 416 | delNode: function delNode(node) { 417 | var isNo = this.beforeDelNode(node); 418 | if (isNo !== 'no') { 419 | if (this.parent == null) throw new Error('the root element can\'t deleted!'); 420 | if (node.checked && this.canCheck) throw new Error('the node should be checked!'); 421 | this.parent.children.splice(this.parent.children.indexOf(node), 1); 422 | this.afterDelNode(node); 423 | } 424 | }, 425 | allCheck: function allCheck(node, state) { 426 | if (node.hasOwnProperty('children')) { 427 | var _iteratorNormalCompletion3 = true; 428 | var _didIteratorError3 = false; 429 | var _iteratorError3 = undefined; 430 | 431 | try { 432 | for (var _iterator3 = node.children[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { 433 | var chilren = _step3.value; 434 | 435 | this.$set(chilren, 'checked', state); 436 | if (chilren.children) return this.allCheck(chilren, state); 437 | } 438 | } catch (err) { 439 | _didIteratorError3 = true; 440 | _iteratorError3 = err; 441 | } finally { 442 | try { 443 | if (!_iteratorNormalCompletion3 && _iterator3.return) { 444 | _iterator3.return(); 445 | } 446 | } finally { 447 | if (_didIteratorError3) { 448 | throw _iteratorError3; 449 | } 450 | } 451 | } 452 | } 453 | }, 454 | nodeCheck: function nodeCheck(node, state) { 455 | if (!node.checked) { 456 | this.$set(node, 'checked', state); 457 | this.allCheck(node, state); 458 | } else { 459 | this.$set(node, 'checked', !state); 460 | this.allCheck(node, !state); 461 | } 462 | } 463 | } 464 | }; 465 | 466 | var VueTrees = { 467 | install: function install(Vue, options) { 468 | Vue.component('vueTrees', Trees); 469 | } 470 | }; 471 | 472 | if (typeof window !== 'undefined' && window.Vue) { 473 | window.Vue.use(VueTrees); 474 | } 475 | 476 | return VueTrees; 477 | 478 | }))); 479 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-trees", 3 | "version": "1.2.3", 4 | "description": "tree UI base on Vue", 5 | "main": "dist/vue-trees.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "build": "rollup -c" 11 | }, 12 | "author": "wang <775100096@qq.com>", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "babel-core": "^6.26.0", 16 | "babel-preset-es2015-rollup": "^3.0.0", 17 | "qrious": "^4.0.2", 18 | "rollup": "^0.55.5", 19 | "rollup-plugin-babel": "^3.0.3", 20 | "rollup-plugin-commonjs": "^8.3.0", 21 | "rollup-plugin-node-resolve": "^3.0.2", 22 | "rollup-plugin-postcss": "^1.2.8", 23 | "rollup-plugin-vue": "^3.0.0", 24 | "vue-template-compiler": "^2.5.13" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import vue from 'rollup-plugin-vue' 2 | import babel from 'rollup-plugin-babel' 3 | import resolve from 'rollup-plugin-node-resolve' 4 | import commonjs from 'rollup-plugin-commonjs' 5 | import postcss from 'rollup-plugin-postcss'; 6 | 7 | export default { 8 | input: './src/vue-trees.js', 9 | output: { 10 | file: 'dist/vue-trees.js', 11 | format: 'umd' 12 | }, 13 | plugins: [ 14 | resolve(), 15 | vue(), 16 | commonjs(), 17 | postcss({ 18 | extensions: ['.css'] 19 | }), 20 | babel({ 21 | exclude: 'node_modules/**', 22 | presets: ['es2015-rollup'] 23 | }), 24 | ], 25 | moduleName: 'vue-trees' 26 | } -------------------------------------------------------------------------------- /src/components/default.css: -------------------------------------------------------------------------------- 1 | .wyr-trees-dfault ul,.wyr-trees-dfault li { 2 | list-style-type:none; 3 | text-align:left; 4 | } 5 | 6 | .wyr-trees-dfault .tree-open { 7 | line-height: 13px; 8 | } 9 | 10 | .wyr-trees-dfault .tree-open:after { 11 | content: "\2013"; 12 | font-style: normal; 13 | } 14 | 15 | .wyr-trees-dfault .tree-close:after { 16 | content: "+"; 17 | font-style: normal; 18 | } 19 | 20 | .wyr-trees-dfault .tree-open, 21 | .wyr-trees-dfault .tree-close { 22 | display: inline-block; 23 | width:14px; 24 | height:14px; 25 | text-align: center; 26 | line-height: 13px; 27 | border: 1px solid #888888; 28 | border-radius: 2px; 29 | background: #FFFFFF; 30 | } 31 | 32 | .wyr-trees-dfault .tree-open:after { 33 | content: "\2013"; 34 | font-style: normal; 35 | } 36 | .wyr-trees-dfault .tree-add { 37 | padding: 5px 10px; 38 | background-color: #00FF99; 39 | color: white; 40 | font-weight: bold; 41 | cursor: pointer; 42 | } 43 | .wyr-trees-dfault .tree-del { 44 | padding: 5px 10px; 45 | background-color: #990033; 46 | color: white; 47 | font-weight: bold; 48 | cursor: pointer; 49 | } 50 | .wyr-trees-dfault .tree-exit { 51 | padding: 5px 10px; 52 | background-color: #CCFF66; 53 | color: white; 54 | font-weight: bold; 55 | cursor: pointer; 56 | } 57 | .wyr-trees-dfault .tree-open { 58 | line-height: 13px; 59 | } 60 | 61 | .wyr-trees-dfault .box-halfchecked { 62 | background-color: #888888; 63 | } 64 | .wyr-trees-dfault .box-halfchecked:after { 65 | content:"\2713"; 66 | display:block; 67 | position:absolute; 68 | z-index:1; 69 | width:100%; 70 | text-align:center; 71 | color: #FFFFFF; 72 | } 73 | .wyr-trees-dfault .inputCheck.wyr-trees-dfault:after { 74 | content:"\2713"; 75 | display:block; 76 | position:absolute; 77 | z-index:1; 78 | width:100%; 79 | text-align:center; 80 | } 81 | .wyr-trees-dfault .check{ 82 | display:block; 83 | position:absolute; 84 | font-size:14px; 85 | width:16px; 86 | height:16px; 87 | left:-5px; 88 | top:-4px; 89 | border:1px solid #000000; 90 | opacity:0; 91 | cursor:pointer; 92 | -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 93 | filter:alpha(opacity=0); 94 | z-index:2; 95 | } 96 | .wyr-trees-dfault .chkDisabled { 97 | background-color: #F5F5F5; 98 | opacity: 1; 99 | cursor: not-allowed; 100 | } 101 | 102 | .wyr-trees-dfault li span:hover { 103 | background-color: #dddddde3 104 | } 105 | .wyr-trees-dfault ul,.wyr-trees-dfault li { 106 | list-style-type:none; 107 | text-align:left; 108 | } 109 | .wyr-trees-dfault li { 110 | margin: 0; 111 | padding: 5px 5px 5px 15px; 112 | position: relative; 113 | list-style: none; 114 | } 115 | .wyr-trees-dfault li:after, 116 | .wyr-trees-dfault li:before { 117 | content: ''; 118 | left: -8px; 119 | position: absolute; 120 | right: auto; 121 | border-width: 1px 122 | } 123 | .wyr-trees-dfault .is-dashed:before { 124 | border-left: 1px dashed #999; 125 | bottom: 50px; 126 | height: 100%; 127 | top: -8px; 128 | width: 1px; 129 | } 130 | .wyr-trees-dfault .is-solid:before { 131 | border-left: 1px solid #999; 132 | bottom: 50px; 133 | height: 100%; 134 | top: -8px; 135 | width: 1px; 136 | } 137 | .wyr-trees-dfault .is-dashed:after { 138 | border-top: 1px dashed #999; 139 | height: 20px; 140 | top: 17px; 141 | width: 28px 142 | } 143 | .wyr-trees-dfault .is-solid:after { 144 | border-top: 1px solid #999; 145 | height: 20px; 146 | top: 17px; 147 | width: 28px 148 | } 149 | .wyr-trees-dfault li:last-child::before { 150 | height: 26px 151 | } 152 | .wyr-trees-dfault>li.first-node:before { 153 | top: 17px; 154 | } 155 | .wyr-trees-dfault>li.first-node.only-node::before { 156 | border-left: none; 157 | } 158 | .wyr-trees-dfault > ul { 159 | padding-left: 0 160 | } 161 | .wyr-trees-dfault { 162 | padding-left: 17px; 163 | padding-top: 10px; 164 | } 165 | .wyr-trees-dfault li.leaf { 166 | padding-left: 15px; 167 | } 168 | .wyr-trees-dfault li.is-solid:after { 169 | content: ''; 170 | left: -7px; 171 | position: absolute; 172 | right: auto; 173 | border-width: 1px; 174 | border-top: 1px solid #999; 175 | height: 20px; 176 | top: 17px; 177 | width: 25px; 178 | } 179 | .wyr-trees-dfault li.is-dashed:after { 180 | content: ''; 181 | left: -7px; 182 | position: absolute; 183 | right: auto; 184 | border-width: 1px; 185 | border-top: 1px dashed #999; 186 | height: 20px; 187 | top: 17px; 188 | width: 25px; 189 | } 190 | .wyr-trees-dfault .tree-node-leaf { 191 | background-color: #FFFFFF; 192 | padding-left: 2px; 193 | position: relative; 194 | z-index: 3; 195 | } 196 | .wyr-trees-dfault .node-title { 197 | padding: 3px 3px; 198 | border-radius: 3px; 199 | cursor: pointer; 200 | margin: 0 2px; 201 | } 202 | .wyr-trees-dfault>li.first-node:before { 203 | top: 17px; 204 | } 205 | .wyr-trees-dfault>li.first-node.only-node::before { 206 | border-left: none; 207 | } 208 | .wyr-trees-dfault>li.first-node.only-node::before { 209 | border-left: none; 210 | } 211 | .wyr-trees-dfault>li.only-node:after { 212 | border-top: none; 213 | } 214 | 215 | .wyr-trees-dfault .inputCheck { 216 | display:inline-block; 217 | position:relative; 218 | width:14px; 219 | height:14px; 220 | border:1px solid #888888; 221 | border-radius:2px; 222 | top:4px; 223 | text-align:center; 224 | font-size:14px; 225 | line-height:14px; 226 | } 227 | .wyr-trees-dfault .inputCheck.notAllNodes:before { 228 | content:"\2713"; 229 | display:block; 230 | position:absolute; 231 | width:100%; 232 | height:100%; 233 | background-color:#888888; 234 | z-index:1; 235 | color:#ffffff; 236 | } 237 | .wyr-trees-dfault .inputCheck.box-checked:after { 238 | content:"\2713"; 239 | display:block; 240 | position:absolute; 241 | z-index:1; 242 | width:100%; 243 | text-align:center; 244 | } -------------------------------------------------------------------------------- /src/components/fold.css: -------------------------------------------------------------------------------- 1 | .wyr-trees-fold { 2 | padding-left: 0px; 3 | padding-top: 0px; 4 | } 5 | .wyr-trees-fold ul,.wyr-trees-fold li { 6 | list-style-type:none; 7 | text-align:left; 8 | } 9 | .wyr-trees-fold .tree-node-leaf { 10 | background-color: white; 11 | padding: 10px 2px; 12 | /* border-top: 1px solid #ebeef5; */ 13 | border-bottom: 1px solid #ebeef5; 14 | } 15 | .wyr-trees-fold .tree-arrow-right { 16 | display: inline-block; 17 | border-right: 3px solid; border-bottom: 3px solid; 18 | width: 8px; height: 8px; 19 | transform: rotate(-45deg); 20 | transition: transform .3s; 21 | } 22 | .wyr-trees-fold .tree-arrow-down { 23 | display: inline-block; 24 | border-right: 3px solid; border-bottom: 3px solid; 25 | width: 8px; height: 8px; 26 | transform: rotate(45deg); 27 | transition: transform .3s; 28 | } 29 | .wyr-trees-fold .tree-down { 30 | height: 100%; 31 | padding: 0 20px; 32 | float: right; 33 | } 34 | 35 | /* .wyr-trees-fold .node-title { 36 | padding-left: 10px; 37 | } */ -------------------------------------------------------------------------------- /src/components/index.vue: -------------------------------------------------------------------------------- 1 | 54 | 273 | -------------------------------------------------------------------------------- /src/components/transition.js: -------------------------------------------------------------------------------- 1 | const elTransition = '0.3s height ease-in-out, 0.3s padding-top ease-in-out, 0.3s padding-bottom ease-in-out' 2 | 3 | function beforeEnter(el) { 4 | el.style.transition = elTransition 5 | if (!el.dataset) el.dataset = {} 6 | 7 | el.dataset.oldPaddingTop = el.style.paddingTop 8 | el.dataset.oldPaddingBottom = el.style.paddingBottom 9 | 10 | el.style.height = 0 11 | el.style.paddingTop = 0 12 | el.style.paddingBottom = 0 13 | } 14 | function enter(el) { 15 | el.dataset.oldOverflow = el.style.overflow 16 | if (el.scrollHeight !== 0) { 17 | el.style.height = el.scrollHeight + 'px' 18 | el.style.paddingTop = el.dataset.oldPaddingTop 19 | el.style.paddingBottom = el.dataset.oldPaddingBottom 20 | } else { 21 | el.style.height = '' 22 | el.style.paddingTop = el.dataset.oldPaddingTop 23 | el.style.paddingBottom = el.dataset.oldPaddingBottom 24 | } 25 | 26 | el.style.overflow = 'hidden' 27 | } 28 | function afterEnter(el) { 29 | el.style.transition = '' 30 | el.style.height = '' 31 | el.style.overflow = el.dataset.oldOverflow 32 | } 33 | 34 | function beforeLeave(el) { 35 | if (!el.dataset) el.dataset = {} 36 | el.dataset.oldPaddingTop = el.style.paddingTop 37 | el.dataset.oldPaddingBottom = el.style.paddingBottom 38 | el.dataset.oldOverflow = el.style.overflow 39 | 40 | el.style.height = el.scrollHeight + 'px' 41 | el.style.overflow = 'hidden' 42 | } 43 | 44 | function leave(el) { 45 | if (el.scrollHeight !== 0) { 46 | el.style.transition = elTransition 47 | el.style.height = 0 48 | el.style.paddingTop = 0 49 | el.style.paddingBottom = 0 50 | } 51 | } 52 | 53 | function afterLeave(el) { 54 | el.style.transition = '' 55 | el.style.height = '' 56 | el.style.overflow = el.dataset.oldOverflow 57 | el.style.paddingTop = el.dataset.oldPaddingTop 58 | el.style.paddingBottom = el.dataset.oldPaddingBottom 59 | } 60 | 61 | export default { 62 | methods: { 63 | beforeEnter, 64 | enter, 65 | afterEnter, 66 | beforeLeave, 67 | leave, 68 | afterLeave 69 | } 70 | } -------------------------------------------------------------------------------- /src/images/afterMod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wyr1227/vue-trees/c7a3877b13ca5f368f717bf813d35e6619308805/src/images/afterMod.png -------------------------------------------------------------------------------- /src/images/beforeMod.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wyr1227/vue-trees/c7a3877b13ca5f368f717bf813d35e6619308805/src/images/beforeMod.jpg -------------------------------------------------------------------------------- /src/vue-trees.js: -------------------------------------------------------------------------------- 1 | import Trees from './components/index.vue'; 2 | 3 | var VueTrees = { 4 | install(Vue, options) { 5 | Vue.component('vueTrees', Trees) 6 | } 7 | }; 8 | 9 | export default VueTrees; 10 | 11 | if (typeof window !== 'undefined' && window.Vue) { 12 | window.Vue.use(VueTrees) 13 | } 14 | --------------------------------------------------------------------------------