用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
沒有留言:
張貼留言