Omi框架可以以少許的代碼聲明式地編寫可拖拽移動節點的樹形組件。
一般樹組件可以考驗UI框架的健壯性,由於須要使用到UI框架的以下特性:html
下面來介紹下使用 omi-tree 的開發全過程。你也能夠無視文章,先體驗一把和直接編輯源碼試一把:node
樹的數據規則:github
{ name: 'Root', children: [ { name: 'A', id: 1, children: [ { id: 4, name: 'A1', children: [] }, { id: 7, name: 'A2', children: [] } ] }, { name: 'B', id: 2, children: [ { id: 5, name: 'B1', children: [] }, { id: 8, name: 'B2', children: [] } ] }, { name: 'C', id: 3, children: [ { id: 6, name: 'C1', children: [] }, { id: 9, name: 'C2', children: [] } ] } ] }
能夠看到,每一個節點都有惟一的id來標識,每一個節點也有children屬性來存放本身的子節點的信息。web
tree結構:框架
<ul> <tree-node o-repeat="child in children" group-data="data.children"></tree-node> </ul>
這裏須要特別注意的是:dom
tree-node結構:this
<li data-node-id="{{id}}" draggable="true" ondragstart="dragStartHandler" ondragleave="dragLeaveHandler" ondrop="dropHandler" ondragover="dragOverHandler" > <div data-node-id="{{id}}">{{name}}</div> <ul data-node-id="{{id}}" o-if="children.length > 0"> <tree-node o-repeat="child in children" group-data="data.children"></tree-node> </ul> </li>
能夠看到每一個tree-node都標記了draggable表明能夠拖拽,drag和drop的支持狀況你們能夠caniuse一把。code
先看tree:htm
class Tree extends Omi.Component { //移動節點 moveNode(id, parentId) { if (id === parentId) { return } if(this.check(parentId, id)) { let parent = this.getChildById(parentId, this.data.children) let child = this.removeChildById(id, this.data.children) parent.children.push(child) this.update() } } //驗證子節點的孩子節點是否包含父親節點,這裏主要是爲了防止把父節點拖拽到本身的孩子節點當中,這是個錯誤的邏輯操做 check(parentId, childId){ let current = this.getChildById(childId, this.data.children), children = current.children for (let i = 0, len = children.length; i < len; i++) { let child = children[i] if (child.id === parentId) { return false } let errorIds = this.check(parentId, child.id ) if (!errorIds) { return false } } return true } //根據id移除child節點數據 removeChildById(id, children) { for (let i = 0, len = children.length; i < len; i++) { let child = children[i] if (child.id === id) { children.splice(i, 1) return child } let target = this.removeChildById(id, child.children) if (target) { return target } } } //根據id獲取child節點數據 getChildById(id, children) { for (let i = 0, len = children.length; i < len; i++) { let child = children[i] if (child.id === id) { return child } let target = this.getChildById(id, child.children) if (target) { return target } } } render() { return `<ul> <tree-node o-repeat="child in children" group-data="data.children"></tree-node> </ul>` } } //生成標籤用於聲明式嵌入其餘組件 Omi.tag('tree', Tree)
下面來看 tree-node:
class TreeNode extends Omi.Component { dropHandler(evt) { //經過evt.dataTransfer.getData接收傳遞過來的數據 this.getRootInstance(this.parent).moveNode(parseInt(evt.dataTransfer.getData("node-id")), parseInt(evt.target.dataset['nodeId'])) this.node && this.node.classList.remove('drag-over') evt.stopPropagation() evt.preventDefault() } getRootInstance(parent){ if(parent.moveNode){ return parent }else{ return this.getRootInstance(parent.parent) } } dragOverHandler(evt){ this.node.classList.add('drag-over') evt.stopPropagation() evt.preventDefault() } dragLeaveHandler(){ this.node.classList.remove('drag-over') } dragStartHandler(evt){ //設置要傳遞的數據 evt.dataTransfer.setData("node-id",this.data.id) evt.stopPropagation() } //局部樣式,drag-over是拖拽在node之上的一個激活樣式 style(){ return ` .drag-over{ border:1px dashed black; } ` } render(){ return ` <li data-node-id="{{id}}" draggable="true" ondragstart="dragStartHandler" ondragleave="dragLeaveHandler" ondrop="dropHandler" ondragover="dragOverHandler" > <div data-node-id="{{id}}">{{name}}</div> <ul data-node-id="{{id}}" o-if="children.length > 0"> <tree-node o-repeat="child in children" group-data="data.children"></tree-node> </ul> </li> ` } } //生成標籤用於聲明式嵌入其餘組件 Omi.tag('tree-node',TreeNode)
到此位置,複雜的拖拽移動都完成了。增刪改查就更加簡單了,你們能夠接着試試~~~