UNPKG

@jambonn/vue-nested-draggable

Version:
323 lines (287 loc) 7.91 kB
# vue-nested-draggable > This is a nested draggable component. This component does not have css, you need to add your style refer to demo. The demo style is less, not difficult. > This component doesn't render node. It exposes a node rendering slot. Please refer to the demo for rendering. **[Full examples](https://jambonn.github.io/vue-nested-draggable/)** # Touch Support touch(single point). ## Indexes - [Installation](#installation) - [Usage](#usage) * [Global](#global) * [Local](#local) * [Data](#data) * [Template](#template) - [Configuration](#configuration) * [Props](#props) * [Hooks](#hooks) * [Tree properties](#properties) * [draggableHelperInfo: {event, options, store}](#draggable_helper_info) * [Events](#events) * [Methods](#methods) * [node properties](#node_properties) * [node deep properties example](#node_deep_properties_example) - [Other](#other) * [Demo css](#demo_css) - [Development](#compiles-and-hot-reloads-for-development) - [License](#license) ## Installation ``` bash npm install @jambonn/vue-nested-draggable ``` or if you prefer yarn ``` bash yarn add @jambonn/vue-nested-draggable ``` ## Usage ### Global You may install Vue Nested Draggable globally: ``` js import Vue from 'vue'; import VueNestedDraggable from '@jambonn/vue-nested-draggable'; Vue.component('draggable-tree', VueNestedDraggable.DraggableTree); ``` This will make **&lt;draggable-tree&gt;** available to all components within your Vue app. ### Local Include the carousel directly into your component using import: ``` js import { DraggableTree } from '@jambonn/vue-nested-draggable'; export default { ... components: { DraggableTree } ... }; ``` ### Data ```js data: [ {text: 'node 1'}, {text: 'node 2'}, {text: 'node 3 undraggable', draggable: false}, {text: 'node 4'}, {text: 'node 4 undroppable', droppable: false}, {text: 'node 5', children: [ {text: 'node 1'}, {text: 'node 2', children: [ {text: 'node 3'}, {text: 'node 4'}, ]}, {text: 'node 2 undroppable', droppable: false, children: [ {text: 'node 3'}, {text: 'node 4'}, ]}, {text: 'node 2', children: [ {text: 'node 3'}, {text: 'node 4 undroppable', droppable: false}, ]}, {text: 'node 3'}, {text: 'node 4'}, {text: 'node 3'}, {text: 'node 4'}, {text: 'node 3'}, {text: 'node 4'}, {text: 'node 3'}, {text: 'node 4'}, ]}, ] ``` ### Template ```template <draggable-tree :data="data" draggable="draggable" crosstree="crossTree"> <div slot-scope="{data, store, vm}"> <template v-if="!data.isDragPlaceHolder"> <b v-if="data.children &amp;&amp; data.children.length" @click="store.toggleOpen(data)"> {{data.open ? &apos;-&apos; : &apos;+&apos;}}&nbsp; </b> <span>{{data.text}}</span> </template> </div> </tree> ``` ## Configuration ### Props ```js // base tree data: {}, // type Array indent: {default: 16}, activatedClass: {default: 'active'}, openedClass: {default: 'open'} space: {default: 10}, // space between node, unit px // draggable tree preventSelect: {default: true}, // if to prevent drag handler text be selected when drag, excluding input and textarea getTriggerEl: {type: Function}, // get the el trigger drag, default is node self. arguments(nodeVm) draggable: {}, // is the tree draggable, default false droppable: {default: true}, // is the tree droppable, default true crossTree: {}, // can a node of the tree be dragged into other tree, or receive other tree node ``` ### Hooks ```js ondragstart: {type: Function}, // hook. return false to prevent drag. arguments(node, draggableHelperInfo) ondragend: {type: Function}, // hook. return false to prevent drop. arguments(node, draggableHelperInfo) ``` ### draggableHelperInfo {event, options, store} ### Properties ```js // base rootData, // generated by tree // draggable dplh, // drag placeholder. globally unique. trees, // array, all trees in the app. globally unique. ``` ### Events ```js // store is the tree vm drag(node), // on drag start. drop(node, targetTree, oldTree), // after drop. change(node, targetTree, oldTree), // after drop, only when the node position changed nodeOpenChanged(node) // on a node is closed or open ``` ### Methods ```js pure(node, withChildren, after) /* pure return a node data without runtime properties.(!: property which starts with '_' will be removed) withChildren: optional. after: Function, optional the code about after(t is computed node data): if (after) { return after(t, node) || t } return t */ getNodeById(id) getActivated() getOpened() activeNode(node, inactiveOld) toggleActive(node, inactiveOld) openNode(node, closeOld) toggleOpen(node, closeOld) // follow methods are easy, so I paste their soure code getPureData(after) { return this.pure(this.rootData, true, after).children } // after: Function, optional deleteNode(node) { return hp.arrayRemove(node.parent.children, node) } // add node: like array. eg: node.children.push(newNodeData) // update node: just assign to the node properties directly isNodeDraggable(node) isNodeDroppable(node) ``` ### Node properties ```js // base _id _vm parent children: [], open, active: false, style: {}, class: '', innerStyle: {}, innerClass: '', innerBackStyle: {}, innerBackClass: {}, // draggable draggable // default true. Please check 'draggable & droppable' below droppable // default true. Please check 'draggable & droppable' below isDragPlaceHolder ``` #### Node deep properties example ```js node._vm // vm node._vm.level // 节点层级, 只读 node._vm.store // tree node.parent._vm // parent node vm node._vm.store ``` #### Node max level ```template <draggable-tree :data="data" draggable="draggable" crosstree="crossTree" @drag="ondrag"> <div slot-scope="{data, store, vm}"> <template v-if="!data.isDragPlaceHolder"> <b v-if="data.children &amp;&amp; data.children.length" @click="store.toggleOpen(data)"> {{data.open ? &apos;-&apos; : &apos;+&apos;}}&nbsp; </b> <span>{{data.text}}</span> </template> </div> </tree> ``` ``` js import { DraggableTree, depthFirstSearch } from '@jambonn/vue-nested-draggable'; export default { ... components: { DraggableTree }, methods: { ondrag(node) { const maxLevel = 2 let nodeLevels = 1 depthFirstSearch(node, childNode => { if (childNode._vm.level > nodeLevels) { nodeLevels = childNode._vm.level } }) nodeLevels = nodeLevels - node._vm.level + 1 const childNodeMaxLevel = maxLevel - nodeLevels depthFirstSearch(this.originalData, childNode => { if (childNode === node) { return 'skip children' } if (!childNode._vm) { console.log(childNode) } this.$set( childNode, 'droppable', childNode._vm.level <= childNodeMaxLevel, ) }) }, }, ... }; ``` # Other ### Demo css ```css .he-tree{ border: 1px solid #ccc; padding: 20px; width: 300px; } .tree-node-inner{ padding: 5px; border: 1px solid #ccc; cursor: pointer; } .draggable-placeholder-inner{ border: 1px dashed #0088F8; box-sizing: border-box; background: rgba(0, 136, 249, 0.09); color: #0088f9; text-align: center; padding: 0; display: flex; align-items: center; } ``` ## Project setup ``` yarn install ``` ### Compiles and hot-reloads for development ``` yarn serve ``` ### Compiles and minifies for production ``` yarn build ``` ### Lints and fixes files ``` yarn lint ``` ### License This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.