Element-ui樹形控制元件el-tree自定義增刪改和區域性重新整理及懶載入操作
阿新 • • 發佈:2020-09-01
需求: vue-cli專案樹形控制元件:一級節點為本地節點,預設展開一級節點,增刪改後區域性重新整理資料。
增加節點,點選確定後區域性重新整理,渲染新資料。
原始碼
element元件樣式
<el-tree class="treeitems" :data="data" node-key="id" :props="defaultProps" :load="loadNode" lazy :default-expanded-keys="[0]" @node-click="handleNodeClick" draggable :allow-drop="allowDrop" :allow-drag="allowDrag" @node-drop="handleDrop" ref="tree" > <span class="custom-tree-node" slot-scope="{ node,data }"> <span>{{ node.label }}</span> <span> <i @click="() => append(node,data)" class="el-icon-plus"></i><!--增加分組--> <!-- 根節點不需要刪除和重新命名 --> <i v-if="data.id !== 0" @click="() => deletes(node,data)" class="el-icon-delete"></i><!--刪除分組--> <i v-if="data.id !== 0" @click="() => rename(node,data)" class="el-icon-edit"></i><!--重新命名分組--> </span> </span> </el-tree>
data資料
data() { return { filterText: '',data: [{ id:0,label: '中國',}],children: [{ id:1,label: '北京',children: [{ id:11,label: '通州' }] },{ id:2,label: '上海',leaf: true,},{ id:3,label: '山西',children:[{ id: 13,label: '太原' },{ id: 14,label: '陽泉' }] },{ id:4,label: '黑龍江',children: [{ id:12,label: '哈爾濱' }] }],defaultProps: { children: 'children',label: 'label',isLeaf: 'leaf' } };
點選增加節點彈出彈窗
這裡也用的是element的彈窗,直接在methods裡寫:
//點重新命名事件 append(node,data) { console.log(node,data,'增加') this.$prompt('節點名字','增加節點',{ confirmButtonText: '確定',cancelButtonText: '取消',inputPattern: /^[\u4e00-\u9fa5]{0,}$/,//匹配全中文 inputErrorMessage: '請輸入中文'//不符合正則匹配的提示語句 }).then(({ value }) => { //可以在這裡發請求,http是我模擬的一個虛假的封裝好的axios請求,()可寫請求引數 http().then((data)=>{ this.$message({ type: 'success',message: '修改成功' }); //請求成功需區域性重新整理該節點,呼叫方法,把節點資訊node傳入 this.partialRefresh(node) }) //請求失敗 .catch(()=>{ this.$message({ type: 'info',message: '修改失敗' }); }) }).catch(() => { this.$message({ type: 'info',message: '取消修改' }); }); },//實現區域性重新整理,在點選彈窗處呼叫的 partialRefreshpartialRefresh(node){ //設定loaded為false;模擬一次節點展開事件,載入重新命名後的新資料; node.loaded = false; node.expand(); //新建子節點是重新整理一次本節點的展開請求,而重新命名和刪除則需要重新整理父級節點的的展開事件, //可以設定node.parent.loaded = false;node.parent.expand(); },
懶載入
該處可直接設定有無節點,如果後端返回有無節點的表示就可用,若無可捨棄。(data中寫,我在本地模擬資料上海欄位中加了leaf: true,上海節點就預設沒有節點了)
//懶載入 loadNode(node,resolve){ if (node.level === 0) { //本地的資料,一個承載中國字樣的陣列; return resolve(this.data); } else if(node.level === 1){ //現在為模擬資料; //有真實資料,在resolve中放置請求回來的資料即可。 //else同樣也是。我這裡是區分了兩種請求方式。 return resolve(this.children) } else{ return resolve([]) } },
拖拽節點
//拖拽==>拖拽時判定目標節點能否被放置 allowDrop(draggingNode,dropNode,type){ //引數:被拖拽節點,要拖拽到的位置 //因為根目錄是我本地寫死的,不能有同級,所以我設定凡是拖拽到的level===1都存放到根節點的下面; if(dropNode.level===1){ return type == 'inner'; } else { return true; } },//拖拽==>判斷節點能否被拖拽 allowDrag(draggingNode){ //第一級節點不允許拖拽 return draggingNode.level !== 1; },
需求改了,同級節點拖拽,拖拽完成後將排序結果返回後端:
//拖拽==>拖拽時判定目標節點能否被放置 //後更改為只能同級拖拽 allowDrop(draggingNode,type) { if (draggingNode.level === dropNode.level) { if (draggingNode.data.parentId === dropNode.data.parentId) { return type === 'prev' || type === 'next' } } else { // 不同級不允許拖拽 return false } },//拖拽==>判斷節點能否被拖拽 allowDrag(draggingNode) { return draggingNode.level !== 1; },//拖拽成功完成時觸發的事件,在這裡可以將節點拖拽後的順序返給後端 handleDrop(node,type,event){ let arr=[]; //data為拖拽後節點資訊,找到它的父級,在從父級找子集 let child = data.parent.childNodes; for(var key in child){ arr.push({id:child[key].data.id}) } //轉為JSON字串發請求帶走資訊 idSort(JSON.stringify(arr)) }
補充知識:vue+element tree ----增加修改刪除上下移動
<template> <div> <div class="exam_structure"> <el-input placeholder="輸入關鍵字進行過濾" v-model="filterText"> </el-input> <el-button type="primary" size="small" class="add_new_question" @click="add_new_question"><i></i>新增父節點</el-button> </div> <div class="question_info_lists"> <el-tree ref="tree" :key="tree_key" :data="treeData" node-key="id" :render-content="renderContent" :expand-on-click-node="false" :default-expanded-keys="defaultExpand" show-checkbox :filter-node-method="filterNode"></el-tree> <el-row class="add_question" v-show="add_question_flag"> <el-col :span="12"> <el-input v-model="new_question_name" placeholder="請輸入大題名稱"></el-input> </el-col> <el-col :span="12"> <el-button size="mini" class="btn_sure" @click.stop="add_question_sure">確定</el-button> <el-button size="mini" class="btn_cancel" @click.stop="add_question_cancel">取消</el-button> </el-col> </el-row> </div> </div> </template> <script> export default { name: "tree1",watch: { filterText(val) { this.$refs.tree.filter(val); } },methods: { filterNode(value,data) { if (!value) return true; return data.label.indexOf(value) !== -1; },// 新增新大題 add_new_question() { this.add_question_flag = true },add_question_sure() { //確定 const nodeObj = {id: '',label: this.new_question_name,isEdit: false,children: []} this.treeData.push(nodeObj) this.add_question_flag = false },add_question_cancel() { //取消 this.add_question_flag = false this.new_question_name = '' },// 增加 append(store,node,data) { var maxid = '20' //新增資料 const nodeapp = {id: ++maxid,label: '增加節點',children: []} data.children.push(nodeapp) if (!node.expanded) { node.expanded = true } const parent = node.parent const children = parent.data const cIndex = children.findIndex(d => d.id === data.id) const tempChildrenNodex2 = children[cIndex] //拿到被新增的上一級 console.log(tempChildrenNodex2.children[cIndex - 1]) },// 修改 nodeEdit(ev,store,data) { data.isEdit = true this.$nextTick(() => { const $input = ev.target.parentNode.parentNode.querySelector('input') || ev.target.parentElement.parentElement.querySelector('input') !$input ? '' : $input.focus() }) },edit_sure(ev,data) { const $input = ev.target.parentNode.parentNode.querySelector('input') || ev.target.parentElement.parentElement.querySelector('input') if (!$input) { return false } else { data.label = $input.value data.isEdit = false } },// 節點刪除 nodeDelete(node,data) { const parent = node.parent const children = parent.data.children || parent.data const index = children.findIndex(d => d.id === data.id) children.splice(index,1) },// 節點上移 nodeUp(node,data) { const parent = node.parent const children = parent.data.children || parent.data const cIndex = children.findIndex(d => d.id === data.id) if (parent.level === 0 && cIndex === 0) { return } else if (parent.level !== 0 && cIndex === 0) { //不同父節點中移動 alert('不同父節點中移動') // const parent2 = parent.parent // const children2 = parent2.data.children || parent2.data // const pIndex2 = parseInt(children2.findIndex(p => p.id === parent.data.id),10) - 1 // if (pIndex2 < 0) return // children2[pIndex2].children.push(data) // children.splice(cIndex,1) // this.defaultExpand[0] = children2[pIndex2].id } else if ((parent.level === 0 && cIndex !== 0) || (parent.level !== 0 && cIndex !== 0)) { const tempChildrenNodex1 = children[cIndex - 1] const tempChildrenNodex2 = children[cIndex] this.$set(children,cIndex - 1,tempChildrenNodex2) this.$set(children,cIndex,tempChildrenNodex1) this.defaultExpand[0] = data.id } this.tree_key++ },// 節點下移 nodeDown(store,data) { const parent = node.parent const children = parent.data.children || parent.data const cIndex = children.findIndex(d => d.id === data.id) const cLength = children.length - 1 // 最邊上的節點 const allLevel = store.data.length - 1 // 樹的深度 if (parent.level === allLevel && cIndex === cLength) { // 最最末的節點 return } else if (parent.level !== allLevel && cIndex === cLength) { //父節點不同 alert('不能移動') // const parent2 = parent.parent // const children2 = parent2.data.children || parent2.data // const pIndex2 = parseInt((children2.findIndex(p => p.id === parent.data.id)),10) // if (pIndex2 === allLevel) return // children2[pIndex2 + 1].children.push(data) // children.splice(cIndex,1) // this.defaultExpand[0] = children2[pIndex2 + 1].id } else if ((parent.level === allLevel && cIndex !== cLength) || (parent.level !== allLevel && cIndex !== cLength)) { // 父節點相同 const tempChildrenNodex1 = children[cIndex + 1] const tempChildrenNodex2 = children[cIndex] this.$set(children,cIndex + 1,tempChildrenNodex1) this.defaultExpand[0] = data.id } this.tree_key++ },showOrEdit(data) { if (data.isEdit) { return <input type="text" value={data.label} on-blur={ev => this.edit_sure(ev,data)}/> } else { return <span className="node_labe">{data.label}</span> } },// 結構樹操作group node,renderContent(h,{node,store}) { return ( <span> <span class="el-icon-document"> {this.showOrEdit(data)} </span> <div class="tree_node_op" style=" float: right"> <i class="el-icon-edit" on-click={(ev) => this.nodeEdit(ev,data)}></i> <i class="el-icon-delete" on-click={() => this.nodeDelete(node,data)}></i> <i class="el-icon-upload2" on-click={() => this.nodeUp(node,data)}></i> <i class="el-icon-download" on-click={() => this.nodeDown(store,data)}></i> <i class="el-icon-plus" on-click={() => this.append(store,data)}></i> </div> </span>) } },data() { return { filterText: '',treeData: [{ id: 1,label: '一級 1',children: [{ id: 4,label: '二級 1-1',children: [{id: 9,label: '三級 1-1-1',children: []},{ id: 10,label: '三級 1-1-2',children: [] },{ id: 11,label: '三級 1-1-3',children: [] }] },{ id: 12,label: '二級 1-2',children: [] },{ id: 13,label: '二級 1-3',children: [] }] },{ id: 2,label: '一級 2',children: [{id: 5,label: '二級 2-1',{ id: 6,label: '二級 2-2',{ id: 3,label: '一級 3',children: [ {id: 7,label: '二級 3-1',{ id: 8,label: '二級 3-2',children: [] }] }],add_question_flag: false,new_question_name: '',tree_key: 0,defaultExpand: [] } },} </script> <style scoped> </style>
以上這篇Element-ui樹形控制元件el-tree自定義增刪改和區域性重新整理及懶載入操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。