1. 程式人生 > 實用技巧 >vue可拖拽樹

vue可拖拽樹

注:自用,一些樣式其他人可能沒有

<!-- Vue SFC -->
<template>
  <div class="container bxs">
    <div class="ct-inner bxs">
      <div class="ct-inner-fiexd w">
        <el-input placeholder="請輸入關鍵詞" suffix-icon="el-icon-search" v-model="filterText"></el-input>
        <
div class="w clearfix tc mt10"> <el-button class="fll" type="primary" plain size="mini">重新整理</el-button> <el-button type="primary" plain size="mini" @click="unFoldAll">全部展開</el-button> <el-button class="flr" type="primary" plain size="mini" @click
="collapseAll">全部收起</el-button> </div> </div> <div class="ct-inner-content h"> <!-- show-checkbox 是否展示多選框 --> <!-- :check-on-click-node="true" 點選文字內容是否選中 --> <el-tree v-if="openOrNot" :data="treeData"
node-key="id" :default-expand-all="defaultExpand" :expand-on-click-node="false" @node-click="handleLeftclick" @node-drag-start="handleDragStart" @node-drag-enter="handleDragEnter" @node-drag-leave="handleDragLeave" @node-drag-over="handleDragOver" @node-drag-end="handleDragEnd" @node-drop="handleDrop" @node-contextmenu="rightClick" :filter-node-method="filterNode" draggable :allow-drop="allowDrop" :allow-drag="allowDrag" ref="tree" > <span class="slot-t-node span-ellipsis" slot-scope="{ node, data }"> <span class="span-ellipsis-inner" v-show="!data.isEdit"> <!-- <el-tooltip class="item" effect="dark" :content="node.label" placement="right"> --> <span class="span-ellipsis"> <span class="span-ellipsis" :class="[(selectTreeData&&data.id==selectTreeData.id)? 'slot-t-node--label' : '']" style="vertical-align:middle;" > <i class="iconfont jxintegral-fill"></i> {{node.label}} </span> </span> <!-- </el-tooltip> --> </span> <!-- autofocus --> <span v-show="data.isEdit"> <el-input class="slot-t-input" style="height:28px;" size="mini" v-model="data.label" :ref="'slotTreeInput'+data.id" @blur.stop="NodeBlur(node,data)" @keydown.native.enter="NodeBlur(node,data)" ></el-input> </span> </span> </el-tree> <el-card class="box-card" ref="card" v-show="menuVisible"> <div @click="addSameLevelNode()" v-show="firstLevel"> <i class="el-icon-circle-plus-outline"></i> <span class="ml10">同級增加</span> </div> <div class="add" @click="addChildNode()"> <i class="el-icon-circle-plus-outline"></i> <span class="ml10">子級增加</span> </div> <div class="delete" @click="deleteNode()"> <i class="el-icon-remove-outline"></i> <span class="ml10">刪除節點</span> </div> <div class="edit" @click="editNode()"> <i class="el-icon-edit"></i> <span class="ml10">修改節點</span> </div> </el-card> </div> </div> </div> </template> <script> import axios from "axios"; export default { name: "PersonManageLf", components: {}, data() { return { openOrNot: true, //展開收縮dom掛載切換 defaultExpand: true, //預設全部展開 eleId: "", isShow: false, currentData: "", currentNode: "", menuVisible: false, firstLevel: false, filterText: "", maxexpandId: 4, treeData: [ { id: 1, label: "一級 1", isEdit: false, children: [ { id: 4, label: "二級 1-1", isEdit: false, children: [ { id: 9, label: "三級 1-1-1嗚嗚嗚嗚嗚嗚嗚嗚無無無無無無無無無無無無無無無無無", isEdit: false, }, { id: 10, label: "三級 1-1-2", isEdit: false, }, ], }, ], }, { id: 2, label: "一級 2", isEdit: false, children: [ { id: 5, label: "二級 2-1", isEdit: false, }, { id: 6, label: "二級 2-2", isEdit: false, }, ], }, { id: 3, label: "一級 3", isEdit: false, children: [ { id: 7, label: "二級 3-1", isEdit: false, }, { id: 8, label: "二級 3-2", isEdit: false, children: [ { id: 11, label: "三級 3-2-1", isEdit: false, }, { id: 12, label: "三級 3-2-2", isEdit: false, }, { id: 13, label: "三級 3-2-3", isEdit: false, }, ], }, ], }, ], treeDataCopy: "", // 拖拽結束後驗證後不可拖拽 defaultProps: { children: "children", label: "label", }, selectTreeNode: "", //選中的樹節點,內含父節點 selectTreeData: "", //選中的樹data newAddTreeObjs: {}, //新增節點儲存物件 nowAddTreeNodeid: "", //當前新增節點id }; }, methods: { // 全部展開 unFoldAll() { let self = this; // 將沒有轉換成樹的原資料 let list = this.treeData; for (let i = 0; i < list.length; i++) { // 將沒有轉換成樹的原資料設定key為... 的展開 self.$refs.tree.store.nodesMap[list[i].id].expanded = true; } }, // 全部摺疊 collapseAll() { let self = this; // 將沒有轉換成樹的原資料 let list = this.treeData; for (let i = 0; i < list.length; i++) { self.$refs.tree.store.nodesMap[list[i].id].expanded = false; } }, renderContent(h, { node, data, store }) { console.log(node.label); console.log(data); console.log(store); return ( <div style="display:inline-block;"> <span style="">{node.label}</span> </div> ); }, open() { this.defaultExpand = !this.defaultExpand; this.openOrNot = false; setTimeout(() => { this.openOrNot = true; }, 10); }, NodeBlur(Node, data) { // debugger; console.log(Node, data); if (data.label.length === 0) { this.$message.error("選單名不可為空!"); return false; } else { if (data.isEdit) { this.$set(data, "isEdit", false); console.log(data.isEdit); } this.$nextTick(() => { this.$refs["slotTreeInput" + data.id].$refs.input.focus(); }); } }, // 查詢 filterNode(value, data) { if (!value) return true; return data.label.indexOf(value) !== -1; }, handleDragStart(node, ev) { console.log(this.treeData, ""); console.log("drag start", node); // 如果要阻止拖拽 // if(node.childNodes.length>0){ // console.log("有子節點不能移動") // ev.preventDefault(); // return; // } }, handleDragEnter(draggingNode, dropNode, ev) { console.log("tree drag enter: ", dropNode.label); }, handleDragLeave(draggingNode, dropNode, ev) { console.log("tree drag leave: ", dropNode.label); }, handleDragOver(draggingNode, dropNode, ev) { console.log("tree drag over: ", dropNode.label); }, handleDragEnd(draggingNode, dropNode, dropType, ev) { console.log("tree drag end: ", dropNode && dropNode.label, dropType); }, handleDrop(draggingNode, dropNode, dropType, ev) { console.log("tree drop: ", dropNode.label, dropType); // 拖拽結束後驗證後不可拖拽 // console.log(this.treeData,'樹') // this.treeData=JSON.parse(JSON.stringify(this.treeDataCopy)); }, allowDrop(draggingNode, dropNode, type) { console.log(dropNode.data) if (dropNode.data.label === "二級 3-1") { return type !== "inner"; } else { return true; } }, allowDrag(draggingNode) { return draggingNode.data.label.indexOf("三級 3-2-2") === -1; }, // 滑鼠右擊事件 rightClick(MouseEvent, object, Node, element) { // debugger; console.log(Node); this.currentData = object; this.currentNode = Node; if (Node.level === 1) { this.firstLevel = true; } else { this.firstLevel = false; } this.menuVisible = true; // let menu = document.querySelector('#card') // /* 選單定位基於滑鼠點選位置 */ // menu.style.left = event.clientX + 'px' // menu.style.top = event.clientY + 'px' document.addEventListener("click", this.foo); // console.log(event.clientY); this.$refs.card.$el.style.left = event.clientX + 40 - 250 + "px"; this.$refs.card.$el.style.top = event.clientY + 10 - 165 + "px"; }, // 滑鼠左擊事件 handleLeftclick(data, node) { // console.log(data,'選中的節點') this.selectTreeNode = node; this.selectTreeData = data; this.foo(data.id, true); }, //判斷是否為新增id,且新增id是否為真id sureNewOrOld(id) { //1 表明是舊id,2表示新id,3表示id未返回 id = id + ""; let arrs = id.split("-"); let newAddTreeObjs = this.newAddTreeObjs; if (arrs[0] == "xzjd") { console.log(id); console.log(newAddTreeObjs); console.log(newAddTreeObjs[id]); let idData = newAddTreeObjs[id]; if (idData.id != id) { return 2; } else { // 新增部門,請重新整理列表獲取資訊! this.$message.warning("新增部門,請稍後操作!"); this.selectTreeNode = ""; this.selectTreeData = ""; return 3; } } else { return 1; } }, // 取消滑鼠監聽事件 選單欄 foo(id, havesure) { // havesure判斷是否為左鍵點選 let newAddTreeObjs = this.newAddTreeObjs; this.menuVisible = false; // 要及時關掉監聽,不關掉的是一個坑,不信你試試,雖然前臺顯示的時候沒有啥毛病,加一個alert你就知道了 document.removeEventListener("click", this.foo); if (this.nowAddTreeNodeid) { this.nowAddTreeNodeid = ""; return; } console.log("真正選中的節點"); if (!havesure) { return; } let oldSure = this.sureNewOrOld(id); console.log(oldSure); if (oldSure == 2) { } else if (oldSure == 3) { return; } else { this.changeRightMess(id); } console.log(); }, // 重新整理右側資訊 changeRightMess(id) { this.$emit("sentFather", { id: id }); }, // 增加同級節點事件 addSameLevelNode() { let id = Math.ceil(Math.random() * 1000); let timestamp = Date.parse(new Date()); id = "xzjd-" + id + "-" + timestamp; console.log(id); var data = { id: id, label: "新增節點" }; this.newAddTreeObjs[id] = data; this.nowAddTreeNodeid = id; this.$refs.tree.append(data, this.currentNode.parent); }, // 增加子級節點事件 addChildNode() { console.log(this.currentData); console.log(this.currentNode); // if (this.currentNode.level >= 3) { // this.$message.error("最多隻支援三級!"); // return false; // } let id = Math.ceil(Math.random() * 1000); let timestamp = Date.parse(new Date()); id = "xzjd-" + id + "-" + timestamp; var data = { id: id, label: "新增節點" }; this.newAddTreeObjs[id] = data; this.nowAddTreeNodeid = id; this.$refs.tree.append(data, this.currentNode); }, // 刪除節點 deleteNode() { this.$refs.tree.remove(this.currentNode); }, // 編輯節點 editNode() { // debugger; if (!this.currentData.isEdit) { this.$set(this.currentData, "isEdit", true); } }, }, watch: { filterText(val) { this.$refs.tree.filter(val); }, }, mounted() { // this.test(); // 拖拽結束後驗證後不可拖拽 // this.treeDataCopy=JSON.parse(JSON.stringify(this.treeData)) }, }; </script> <style lang="scss" scoped> .container { height: 95%; .ct-inner { height: 100%; position: relative; padding-top: 84px; .ct-inner-fiexd { position: absolute; left: 0; top: 0; } .ct-inner-content { // overflow: hidden; .text { font-size: 14px; } .add { cursor: pointer; margin-top: 10px; } .delete { margin: 10px 0; cursor: pointer; } .edit { margin-bottom: 10px; cursor: pointer; } .box-card { width: 140px; position: absolute; z-index: 1000; } .slot-t-node--label { background-color: #f5f7fa; } } } } .span-ellipsis { width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; display: inline-block; } </style> <style > .el-tree { width: 100%; max-height: 95%; padding-bottom: 20px; overflow: auto; } .el-tree > .el-tree-node { display: inline-block; min-width: 100%; } .el-tree-node__content { height: 30px; } </style>