Element-ui樹形控件el-tree自定義增刪改和局部刷新及懶加載操作
需求: vue-cli項(xiàng)目樹形控件:一級節(jié)點(diǎn)為本地節(jié)點(diǎn),默認(rèn)展開一級節(jié)點(diǎn),增刪改后局部刷新數(shù)據(jù)。
增加節(jié)點(diǎn),點(diǎn)擊確定后局部刷新,渲染新數(shù)據(jù)。
源碼
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><!--增加分組--> <!-- 根節(jié)點(diǎn)不需要刪除和重命名 --> <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數(shù)據(jù)
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' } };
點(diǎn)擊增加節(jié)點(diǎn)彈出彈窗
這里也用的是element的彈窗,直接在methods里寫:
//點(diǎn)重命名事件 append(node,data) { console.log(node,data,'增加') this.$prompt('節(jié)點(diǎn)名字', '增加節(jié)點(diǎn)', { confirmButtonText: '確定', cancelButtonText: '取消', inputPattern: /^[\u4e00-\u9fa5]{0,}$/,//匹配全中文 inputErrorMessage: '請輸入中文'//不符合正則匹配的提示語句 }).then(({ value }) => { //可以在這里發(fā)請求,http是我模擬的一個虛假的封裝好的axios請求,()可寫請求參數(shù) http().then((data)=>{ this.$message({ type: 'success', message: '修改成功' }); //請求成功需局部刷新該節(jié)點(diǎn),調(diào)用方法,把節(jié)點(diǎn)信息node傳入 this.partialRefresh(node) }) //請求失敗 .catch(()=>{ this.$message({ type: 'info', message: '修改失敗' }); }) }).catch(() => { this.$message({ type: 'info', message: '取消修改' }); }); }, //實(shí)現(xiàn)局部刷新,在點(diǎn)擊彈窗處調(diào)用的 partialRefreshpartialRefresh(node){ //設(shè)置loaded為false;模擬一次節(jié)點(diǎn)展開事件,加載重命名后的新數(shù)據(jù); node.loaded = false; node.expand(); //新建子節(jié)點(diǎn)是刷新一次本節(jié)點(diǎn)的展開請求,而重命名和刪除則需要刷新父級節(jié)點(diǎn)的的展開事件, //可以設(shè)置node.parent.loaded = false;node.parent.expand(); },
懶加載
該處可直接設(shè)置有無節(jié)點(diǎn),如果后端返回有無節(jié)點(diǎn)的表示就可用,若無可舍棄。(data中寫,我在本地模擬數(shù)據(jù)上海字段中加了leaf: true,上海節(jié)點(diǎn)就默認(rèn)沒有節(jié)點(diǎn)了)
//懶加載 loadNode(node, resolve){ if (node.level === 0) { //本地的數(shù)據(jù),一個承載中國字樣的數(shù)組; return resolve(this.data); } else if(node.level === 1){ //現(xiàn)在為模擬數(shù)據(jù); //有真實(shí)數(shù)據(jù),在resolve中放置請求回來的數(shù)據(jù)即可。 //else同樣也是。我這里是區(qū)分了兩種請求方式。 return resolve(this.children) } else{ return resolve([]) } },
拖拽節(jié)點(diǎn)
//拖拽==>拖拽時(shí)判定目標(biāo)節(jié)點(diǎn)能否被放置 allowDrop(draggingNode, dropNode, type){ //參數(shù):被拖拽節(jié)點(diǎn),要拖拽到的位置 //因?yàn)楦夸浭俏冶镜貙懰赖模荒苡型?,所以我設(shè)置凡是拖拽到的level===1都存放到根節(jié)點(diǎn)的下面; if(dropNode.level===1){ return type == 'inner'; } else { return true; } }, //拖拽==>判斷節(jié)點(diǎn)能否被拖拽 allowDrag(draggingNode){ //第一級節(jié)點(diǎn)不允許拖拽 return draggingNode.level !== 1; },
需求改了,同級節(jié)點(diǎn)拖拽,拖拽完成后將排序結(jié)果返回后端:
//拖拽==>拖拽時(shí)判定目標(biāo)節(jié)點(diǎn)能否被放置 //后更改為只能同級拖拽 allowDrop(draggingNode, dropNode, type) { if (draggingNode.level === dropNode.level) { if (draggingNode.data.parentId === dropNode.data.parentId) { return type === 'prev' || type === 'next' } } else { // 不同級不允許拖拽 return false } }, //拖拽==>判斷節(jié)點(diǎn)能否被拖拽 allowDrag(draggingNode) { return draggingNode.level !== 1; }, //拖拽成功完成時(shí)觸發(fā)的事件,在這里可以將節(jié)點(diǎn)拖拽后的順序返給后端 handleDrop(node,data,type,event){ let arr=[]; //data為拖拽后節(jié)點(diǎn)信息,找到它的父級,在從父級找子集 let child = data.parent.childNodes; for(var key in child){ arr.push({id:child[key].data.id}) } //轉(zhuǎn)為JSON字符串發(fā)請求帶走信息 idSort(JSON.stringify(arr)) }
補(bǔ)充知識:vue+element tree ----增加修改刪除上下移動
<template> <div> <div class="exam_structure"> <el-input placeholder="輸入關(guān)鍵字進(jìn)行過濾" v-model="filterText"> </el-input> <el-button type="primary" size="small" class="add_new_question" @click="add_new_question"><i></i>添加父節(jié)點(diǎn)</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' //新增數(shù)據(jù) const nodeapp = {id: ++maxid, label: '增加節(jié)點(diǎn)', isEdit: false, 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 } }, // 節(jié)點(diǎn)刪除 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) }, // 節(jié)點(diǎn)上移 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) { //不同父節(jié)點(diǎn)中移動 alert('不同父節(jié)點(diǎn)中移動') // 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++ }, // 節(jié)點(diǎn)下移 nodeDown(store, node, 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 // 最邊上的節(jié)點(diǎn) const allLevel = store.data.length - 1 // 樹的深度 if (parent.level === allLevel && cIndex === cLength) { // 最最末的節(jié)點(diǎn) return } else if (parent.level !== allLevel && cIndex === cLength) { //父節(jié)點(diǎn)不同 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)) { // 父節(jié)點(diǎn)相同 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++ }, 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> } }, // 結(jié)構(gòu)樹操作group node, renderContent(h, {node, data, 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, store, 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, node, data)}></i> <i class="el-icon-plus" on-click={() => this.append(store, node, data)}></i> </div> </span>) } } , data() { return { filterText: '', treeData: [{ id: 1, label: '一級 1', isEdit: false, children: [{ id: 4, label: '二級 1-1', isEdit: false, children: [{id: 9, label: '三級 1-1-1', isEdit: false, children: []}, { id: 10, label: '三級 1-1-2', isEdit: false, children: [] }, { id: 11, label: '三級 1-1-3', isEdit: false, children: [] }] }, { id: 12, label: '二級 1-2', isEdit: false, children: [] }, { id: 13, label: '二級 1-3', isEdit: false, children: [] }] }, { id: 2, label: '一級 2', isEdit: false, children: [{id: 5, label: '二級 2-1', isEdit: false, children: []}, { id: 6, label: '二級 2-2', isEdit: false, children: [] }] }, { id: 3, label: '一級 3', isEdit: false, children: [ {id: 7, label: '二級 3-1', isEdit: false, children: []}, { id: 8, label: '二級 3-2', isEdit: false, children: [] }] }], add_question_flag: false, new_question_name: '', tree_key: 0, defaultExpand: [] } }, } </script> <style scoped> </style>
以上這篇Element-ui樹形控件el-tree自定義增刪改和局部刷新及懶加載操作就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Vue2利用Axios發(fā)起請求的詳細(xì)過程記錄
有很多時(shí)候你在構(gòu)建應(yīng)用時(shí)需要訪問一個API并展示其數(shù)據(jù),做這件事的方法有好幾種,而使用基于promise的HTTP客戶端axios則是其中非常流行的一種,這篇文章主要給大家介紹了關(guān)于Vue2利用Axios發(fā)起請求的詳細(xì)過程,需要的朋友可以參考下2021-12-12Vue動態(tài)設(shè)置圖片時(shí)src不生效的原因及解決方法
這篇文章主要介紹了Vue動態(tài)設(shè)置圖片時(shí)src不生效的原因及解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Vue源碼學(xué)習(xí)defineProperty響應(yīng)式數(shù)據(jù)原理實(shí)現(xiàn)
這篇文章主要為大家介紹了Vue源碼學(xué)習(xí)defineProperty響應(yīng)式數(shù)據(jù)原理實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09