用emit取代Vue.js的treeview事件
前言
在之前的在Vue.js的treeview增加drag功能裡的事件是透過 props 來傳達,但之後又發現有 emit 可以用,最後決定用 emit 取代目前的 props 傳事件,在此做個紀錄。內容
這次的程式碼會整合在Vue.js的treeview增加drag功能與初探Vue.js的emit,整合的程式碼如下HTML 的部分
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script> <div id='app'> <root_treenodeview :rootnode_list='nodelist' @evt-drag-node="onDragNode" @evt-drop-node="onDropNode" @evt-drop-node-parent="onDropNodeParent"></root_treenodeview> </div> </body> </html>
JavaScript 的部分
Vue.component('treenodeview',{ props : ['node'], template : [ '<ul>\n', ' <li>\n', ' <div @click="onClick" draggable="true" @dragstart="onDragStart" @dragover="onDragOver" @drop="onDrop">\n', ' {{node.name}}\n', ' <span v-show="isFolder">[{{isExpand?"-":"+"}}]</span>\n', ' </div>\n', ' </li>\n', ' <div style="height:10px;" @dragenter="onDragEnterParent" @dragover="onDragOverParent" @dragleave="onDragLeaveParent" @drop="onDropParent">\n', ' <hr v-show="isShowDragParent" style="margin:0px;">\n', ' </div>\n', ' <treenodeview v-show="isExpand" v-for="childNode in node.child" :node="childNode" @evt-drag-node="onDragNode" @evt-drop-node="onDropNode" @evt-drop-node-parent="onDropNodeParent"></treenodeview>\n', '</ul>\n' ].join(''), data : function(){ return { isExpand : false, isShowDragParent : false, }; }, computed:{ isFolder:function(){ return this.node.child && this.node.child.length; } }, methods:{ onClick : function(){ if(this.isFolder){ this.isExpand=!this.isExpand; } }, onDragStart : function(evt){ this.$emit('evt-drag-node', this.node); }, onDragOver : function(evt){ evt.preventDefault(); }, onDrop : function(evt){ evt.preventDefault(); this.$emit('evt-drop-node', this.node); }, onDragEnterParent : function(evt){ this.isShowDragParent = true; }, onDragOverParent : function(evt){ evt.preventDefault(); this.isShowDragParent = true; }, onDragLeaveParent : function(evt){ this.isShowDragParent = false; }, onDropParent : function(evt){ evt.preventDefault(); this.isShowDragParent = false; this.$emit('evt-drop-node-parent', this.node); }, onDragNode : function(node){ this.$emit('evt-drag-node', node); }, onDropNode : function(node){ this.$emit('evt-drop-node', node); }, onDropNodeParent : function(node){ this.$emit('evt-drop-node-parent', node); } } }); Vue.component('root_treenodeview',{ props : ['rootnode_list'], template:[ '<div>\n', ' <treenodeview v-for="rootNode in rootnode_list" :node="rootNode" @evt-drag-node="onDragNode" @evt-drop-node="onDropNode" @evt-drop-node-parent="onDropNodeParent"></treenodeview>\n', '</div>\n', ].join(''), methods:{ onDragNode : function(node){ this.$emit('evt-drag-node', node); }, onDropNode : function(node){ this.$emit('evt-drop-node', node); }, onDropNodeParent : function(node){ this.$emit('evt-drop-node-parent', node); } } }); // function Node(opt){ this.name = (opt.name) ? opt.name : ''; this.parent = undefined; this.child = []; } Node.prototype.setParent = function(parentNode){ let isFindInParent = false; let findNode = parentNode; while(findNode){ if(findNode === this){ isFindInParent = true; break; } findNode = findNode.parent; } if(isFindInParent) return; if(this.parent){ // if(isFindInParent) return; let index=-1; for(let i=0;i<this.parent.child.length;i++){ if(this.parent.child[i] === this){ index = i; break; } } // if(index >= 0){ this.parent.child.splice(index,1); } } // this.parent = parentNode; if(parentNode) parentNode.child.push(this); }; let nodeRoot=new Node({name:"root"}); let node1=new Node({name:"node1"}); let node2=new Node({name:"node2"}); node1.setParent(nodeRoot); node2.setParent(node1); let app = new Vue({ el : '#app', data:function(){ return { nodelist:[nodeRoot], dragNode : null } }, methods:{ onDragNode:function(node){ this.dragNode = node; }, onDropNode:function(node){ if(this.dragNode){ if(this.dragNode.parent === undefined){ let index=-1; for(let i=0;i<this.nodeList.length;i++){ if(this.nodeList[i] === this.dragNode){ index = i; break; } } // if(index>=0){ this.nodeList.splice(index,1); } } this.dragNode.setParent(node); } }, onDropNodeParent:function(node){ if(this.dragNode && this.dragNode!==node){ if(node.parent) this.dragNode.setParent(node.parent); else{ this.dragNode.setParent(undefined); this.nodelist.push(this.dragNode); } } } } });
這次會在 treenodeview 與 root_treenodeview都新增 onDragNode 、 onDropNode 與 onDropNodeParent,實作的部分都只是喚起 emit,主要的原因在 初探Vue.js的emit 裡說過只能傳一層,所以這些 emit 其實是往上再傳。
這次的做法有比較好嗎?只是比較接近"官方"用法而已,如果有看過官方寫的 treeview(Tree View Example),裡面的事件傳遞都是用 emit 的方式,而不是用 props 傳事件,所以改成"官方"的用法。
參考資料
Tree View Example相關文章
在Vue.js的treeview增加drag功能初探Vue.js的emit
沒有留言:
張貼留言