赞
踩
主要功能:添加同级、添加子级、拖拽、双击名称进行修改
依赖:vue、element-ui、sass
git地址:https://github.com/rongyanping/vue-tree
<template> <div class="my_tree"> <div class="brother" v-for="(data, idx) of treeData" :key="idx"> <div class="node" @drop="drop($event,treeData,idx)" @dragover="allowDrop($event,treeData,idx)"> <span @click="data.expand=!data.expand"> <i class="el-icon-caret-bottom" v-if="data.expand && data.type==='group'"></i> <i class="el-icon-caret-right" v-if="!data.expand && data.type==='group'"></i> </span> <div :draggable="!data.editable" :class="{'cname_child':true,'cname_child_edit':data.editable}" :contentEditable="data.editable" @dragstart="drag($event,treeData,idx)" @dblclick="dbclickHandle($event,treeData,idx)" @click="data.expand=!data.expand"> {{data.name}} </div> <button class="operation_btn" v-if=" data.type==='group'" @click="addBrother($event,data)">添加同级</button> <button class="operation_btn" v-if=" data.type==='group'" @click="addChild($event,data)">添加子级</button> <button class="operation_btn" v-if=" data.type==='group'" @click="deleteNode($event, data)">删除</button> </div> <div class="children" v-if="data.children && data.children.length" v-show="data.expand"> <my-tree :treeData="data.children" @addBrother="addBrother" @addChild="addChild" @deleteNode="deleteNode" @dragBegin="drag" @dragStop="drop" @dbclickChangeName="dbclickChangeName"> </my-tree> </div> </div> </div> </template> <script> export default { name: 'MyTree', props: { treeData: { type: Array, default: () => [{ id: 1, name: '分组1', expand: true, type:'group', children: [{ id: 2, expand: true, name: '相机1', type:'camera', }] }, { id: 3, expand: true, name: '分组2', type:'group', children: [ { id: 5, expand: true, name: '分组2-1', type:'group', children: [{ id: 6, expand: true, name: '相机2-1', type:'camera', }] }] }] }, }, methods: { // 双击 dbclickHandle(event,data,index){ const _this = this; this.$set(data[index],'editable',true); let target = event.target; setTimeout(function () { target.focus(); let selection = getSelection(); // 判断选定对象范围是编辑框还是文本节点 if(selection.anchorNode.nodeName === '#text'){ // 如果是文本节点则先获取光标对象 let range = selection.getRangeAt(0); // 获取光标对象的范围界定对象,一般就是textNode对象 let textNode = range.startContainer; // 光标移动到到原来的位置加上新内容的长度 rangeStartOffset + range.setStart(textNode, target.innerHTML.length); // 光标开始和光标结束重叠 range.collapse(true); // 清除选定对象的所有光标对象 selection.removeAllRanges(); // 插入新的光标对象 selection.addRange(range); } target.onblur = function () { _this.$emit('dbclickChangeName',data,index,target.innerText); // console.log('失焦---------',target.innerText) } },10); }, // 传给父级新名称 dbclickChangeName(data,index,name){ this.$emit('dbclickChangeName',data,index,name); // console.log('====',name) }, // 开始拖拽 drag(event,data,index){ this.$emit('dragBegin',event,data,index); }, // 拖拽结束 drop(event,data,index){ event.preventDefault(); this.$emit('dragStop',event,data,index); // console.log('drop>>>>>',event,data,index); }, // 在何处放置被拖动的数据 allowDrop(event,data,index){ event.preventDefault(); }, // 添加子级 addChild (event, data) { this.$emit('addChild', event, data) }, // 添加同级 addBrother (event, data) { this.$emit('addBrother', event, data); }, // 删除 deleteNode (event, data) { this.$emit('deleteNode', event, data) }, } } </script> <style scoped lang="scss"> .my_tree{ .brother{ display: flex; flex-direction: column; padding-top: 20px; .node{ display: flex; align-items: center; .cname_child{ border-style: none; outline: none; width: 100px; } .cname_child_edit{ border: 1px solid gray; } .operation_btn{ margin-left: 20px } } .children { position: relative; margin-left: 20px; } } } input[disabled],input:disabled,input.disabled{ color: #333; -webkit-text-fill-color:#333; opacity: 1; background-color:white; } </style>
<template> <div class="tree"> <my-tree @addBrother="addBrother" @addChild="addChild" @deleteNode="deleteNode" :treeData="datas" @dragBegin="drag" @dragStop="drop" @dbclickChangeName="dbclickChangeName"> </my-tree> <div v-show="iptVisible" style="margin-top: 20px"> <span>分组名:</span> <input type="text" v-model="groupName"> <button @click="submitGroup">提交</button> </div> <div v-show="iptVisible2" style="margin-top: 20px"> <span>子级名:</span> <input type="text" v-model="groupName2"> 类型:分组/相机 <input type="text" v-model="addType"> <button @click="submitChild">提交</button> </div> </div> </template> <script> import MyTree from './MyTree' export default { name: 'tree3', components: { 'my-tree': MyTree }, data () { return { id: 100, datas:[{ id: 1, name: '分组1', expand: true, type:'group', editable:false, children: [{ id: 2, expand: true, name: '相机1', type:'camera', editable:false, }] }, { id: 3, expand: true, name: '分组2', type:'group', editable:false, children: [ { id: 5, expand: true, name: '分组2-1', type:'group', editable:false, children: [{ id: 6, expand: true, name: '相机2-1', type:'camera', editable:false, },{ id: 7, expand: true, name: '相机2-2', type:'camera', editable:false, }] }] }], dragData:null, dragEvent:null, dragIndex:null, cid:10, groupName:'', iptVisible:false, brotherData:null, brotherEvent:null, addChildData:null, addChildEvent:null, iptVisible2:false, groupName2:'', addType:'group' } }, methods: { /* 操作数据全部在本组件内部 */ // 接收新名称 dbclickChangeName(data,index,changeName){ // 发送请求:修改名称 this.$set(data[index],'name',changeName); this.$set(data[index],'editable',false); console.log('dbclick=====',changeName); }, /* 拖拽 */ drag(event,data,index){ this.dragData = data; this.dragEvent = event; this.dragIndex = index; // console.log('dragStart=====',this.dragData,index); }, drop(event,data,index){ /* 拖拽只能是拖到某个分组内 成为该分组的子级 */ /* 松开鼠标---调取修改接口,成功后添加新数据,删除之前位置*/ const _this = this; data[index].children.push(this.dragData[this.dragIndex]); // 删除原有数据 setTimeout(function () { console.log('dragOver=====',_this.dragEvent,_this.dragData); _this.deleteNode(_this.dragEvent,_this.dragData[_this.dragIndex]) },10); }, // 添加同级 addBrother (event,data) { this.iptVisible = true; this.id++; this.brotherData = data; this.brotherEvent = event; console.log('addBrother>>>>',this.brotherData); }, submitGroup(){ let parentData = this.getParentData(this.brotherEvent.target); // console.log('parentData========',this.brotherEvent.target); if (parentData) { let index = parentData.indexOf(this.brotherData); if (index !== -1) { parentData.splice(index + 1, 0, { id: this.id, name: this.groupName, expand: false, type:'group', children: [] }) } } }, // 添加子级 addChild (event, data) { this.iptVisible2 = true; this.cid++; this.addChildData = data; console.log(this.addChildData) // // data 父级数据 // console.log('addchild===tree3==',data); // if (!data.children) { // this.$set(data, 'children', []) // } // data.children.push(this.newNode('camera')) // console.log('data====',data) }, submitChild(){ if(!this.addChildData.children){ this.$set(this.addChildData, 'children', []) } if(this.addType==='group'){ this.addChildData.children.push({ id: this.cid, children:[], expand: false, name: this.groupName2, type:'group', }) } else { this.addChildData.children.push({ id: this.cid, expand: true, name: this.groupName2+this.cid, type:'camera', }) } }, // 删除组 deleteNode (event, data) { console.log('del====',event,data) let parentData = this.getParentData(event.target); if (parentData) { let index = parentData.indexOf(data); if (index !== -1) { parentData.splice(index, 1) } } }, newNode (type) { let id = this.id++; return { id, name: type==='group'?'新分组' + id:'新相机'+id, expand: false, children: [], type:type } }, getParentData (node) { while (node && node.tagName !== 'BODY') { // console.log('node=====',node,node.__vue__) if (node.__vue__ && node.__vue__.$options._componentTag === 'my-tree') { return node.__vue__.treeData } node = node.parentNode } return null } } } </script> <style lang="scss" scoped> .tree{ padding: 50px 20px; text-align: left; } .tree-title{ border-bottom: 1px solid gray; padding-bottom: 10px; margin-bottom: 10px; } </style>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。