VUE餓了么樹(shù)形控件添加增刪改功能的示例代碼
本文介紹了VUE餓了么樹(shù)形控件添加增刪改功能的示例代碼,分享給大家,具體如下:
element-ui樹(shù)形控件:地址
在原文檔中有個(gè)案例是有新增和刪除功能,但是后來(lái)發(fā)現(xiàn)其修改的數(shù)據(jù)并不能直接影響到樹(shù)形數(shù)據(jù),所以采用了 render-content 的API重新寫(xiě)了個(gè)組件。
寫(xiě)個(gè)開(kāi)發(fā)的步驟,所以文章比較長(zhǎng)emmm
大致效果如圖:
1.省市API
在網(wǎng)上復(fù)制了個(gè)省市的list,有兩個(gè)屬性是新增的
- isEdit :控制編輯狀態(tài)
- maxexpandId :為現(xiàn)下id的最大值
export default{ maxexpandId: 95, treelist: [{ id: 1, name: "北京市", ProSort: 1, remark: "直轄市", pid: '', isEdit: false, children: [{ id: 35, name: "朝陽(yáng)區(qū)", pid: 1, remark: '', isEdit: false, children: [] }] }{...}] }
2.el-tree Component基本
咱們一步步來(lái),先寫(xiě)個(gè)餓了么的組件
<template> <el-tree ref="expandMenuList" class="expand-tree" v-if="isLoadingTree" :data="setTree" node-key="id" highlight-current :props="defaultProps" :expand-on-click-node="false" :render-content="renderContent" :default-expanded-keys="defaultExpandKeys"></el-tree> </template> <!-- * highlight-current :為了點(diǎn)擊時(shí)節(jié)點(diǎn)高亮 * expand-on-click-node : 只能箭頭控制樹(shù)形的展開(kāi)收縮 * render-content : 節(jié)點(diǎn)渲染方式 * default-expanded-keys :默認(rèn)展開(kāi)節(jié)點(diǎn) -->
同時(shí)引入API和節(jié)點(diǎn)渲染的組件
import TreeRender from '@/components/tree_render' import api from '@/resource/api'
然后搭建好基礎(chǔ)
data(){ return{ maxexpandId: api.maxexpandId,//新增節(jié)點(diǎn)開(kāi)始id non_maxexpandId: api.maxexpandId,//新增節(jié)點(diǎn)開(kāi)始id(不更改) isLoadingTree: false,//是否加載節(jié)點(diǎn)樹(shù) setTree: api.treelist,//節(jié)點(diǎn)樹(shù)數(shù)據(jù) defaultProps: { children: 'children', label: 'name' }, defaultExpandKeys: [],//默認(rèn)展開(kāi)節(jié)點(diǎn)列表 } },
添加個(gè)渲染的method
methods: { renderContent(h,{node,data,store}){ let that = this;//指向vue return h(TreeRender,{ props: { DATA: data,//節(jié)點(diǎn)數(shù)據(jù) NODE: node,//節(jié)點(diǎn)內(nèi)容 STORE: store,//完整樹(shù)形內(nèi)容 }, on: {//綁定方法 nodeAdd: ((s,d,n) => that.handleAdd(s,d,n)), nodeEdit: ((s,d,n) => that.handleEdit(s,d,n)), nodeDel: ((s,d,n) => that.handleDelete(s,d,n)) } }); }, handleAdd(s,d,n){//增加節(jié)點(diǎn) console.log(s,d,n) }, handleEdit(s,d,n){//編輯節(jié)點(diǎn) console.log(s,d,n) }, handleDelete(s,d,n){//刪除節(jié)點(diǎn) console.log(s,d,n) } }
3.tree_render Component基本
渲染組件:
<template> <span class="tree-expand"> <span class="tree-label"> <span>{{DATA.name}}</span> </span> <span class="tree-btn"> <i class="el-icon-plus" @click.stop="nodeAdd(STORE,DATA,NODE)"></i> <i class="el-icon-edit" @click.stop="nodeEdit(STORE,DATA,NODE)"></i> <i class="el-icon-delete" @click.stop="nodeDel(STORE,DATA,NODE)"></i> </span> </span> </template>
添加好幾個(gè)按鈕(element-ui自帶icon:地址)對(duì)應(yīng)的方法:
export default{ props: ['NODE', 'DATA', 'STORE'], methods: { nodeAdd(s,d,n){//新增 this.$emit('nodeAdd',s,d,n) }, nodeEdit(s,d,n){//編輯 this.$emit('nodeEdit',s,d,n) }, nodeDel(s,d,n){//刪除 this.$emit('nodeDel',s,d,n) } } }
4.改
我們用isEdit來(lái)切換input和span的顯示狀態(tài),首先加個(gè)input:
<!-- tree_render component --> <template> <span class="tree-expand"> <span class="tree-label" v-if="DATA.isEdit"> <el-input class="edit" size="mini" :ref="'treeInput'+DATA.id" v-model="DATA.name"></el-input> </span> <template v-else> <span class="tree-label"> <span>{{DATA.name}}</span> </span> <span class="tree-btn" v-show="!DATA.isEdit"> <i class="el-icon-plus" @click.stop="nodeAdd(STORE,DATA,NODE)"></i> <i class="el-icon-edit" @click.stop="nodeEdit(STORE,DATA,NODE)"></i> <i class="el-icon-delete" @click.stop="nodeDel(STORE,DATA,NODE)"></i> </span> </template> </span> </template>
編輯的時(shí)候按鈕同時(shí)消失,那么什么時(shí)候編輯完成呢?
- 編輯完按enter鍵=》監(jiān)聽(tīng)input的enter輸入
- 點(diǎn)擊其他節(jié)點(diǎn)=》input失焦-blur=》編輯時(shí)自動(dòng)聚焦-focus
- 點(diǎn)擊當(dāng)前節(jié)點(diǎn)范圍
當(dāng)以上三點(diǎn)發(fā)生一項(xiàng),節(jié)點(diǎn)對(duì)應(yīng)的data都要isEdit = false;
1、enter鍵
<!-- tree_render component --> <el-input @keyup.enter.native="nodeEditPass(STORE,DATA,NODE)"></el-input>
添加方法:
//tree_render component methods: { nodeEditPass(s,d,n){ d.isEdit = false; } }
2、focus or blur
<!-- tree_render component --> <el-input @blur="nodeEditPass(STORE,DATA,NODE)"></el-input>
后來(lái)發(fā)現(xiàn)第一次編輯時(shí)能讓input聚焦,點(diǎn)擊第二個(gè)input就不起作用了,加了autofocus屬性也同樣如此。所以我們要在點(diǎn)擊編輯icon的時(shí)候,用原生的input autofocus。
修改方法:
//tree_render component nodeEdit(s,d,n){//編輯 d.isEdit = true; this.$nextTick(() => { this.$refs['treeInput'+d.id].$refs.input.focus() }) this.$emit('nodeEdit',s,d,n) }
3、當(dāng)前節(jié)點(diǎn)點(diǎn)擊
采用el-tree已有的API——node-click
<!-- el-tree component --> <el-tree @node-click="handleNodeClick"></el-tree>
添加methods:
//el-tree component methods: { handleNodeClick(d,n,s){//點(diǎn)擊節(jié)點(diǎn) d.isEdit = false;//放棄編輯狀態(tài) } }
問(wèn)題來(lái)了,如果在編輯狀態(tài)下點(diǎn)擊此節(jié)點(diǎn)也同樣會(huì)影響input,這就無(wú)法進(jìn)入編輯,所以要阻止input事件冒泡:
<!-- tree_render component --> <el-input @click.stop.native="nodeEditFocus"></el-input>
添加methods:
//tree_render component methods: { nodeEditFocus(){} }
4、v-show代替v-if
這里有個(gè)新的問(wèn)題,當(dāng)用戶經(jīng)常編輯修改,v-if模板的開(kāi)銷更高,所以改用v-show。而后者不支持template模板,所以要適當(dāng)調(diào)整一下位置:
<template> <span class="tree-expand"> <span class="tree-label" v-show="DATA.isEdit"> <el-input class="edit" size="mini" autofocus v-model="DATA.name" :ref="'treeInput'+DATA.id" @click.stop.native="nodeEditFocus" @blur="nodeEditPass(STORE,DATA,NODE)" @keyup.enter.native="nodeEditPass(STORE,DATA,NODE)"></el-input> </span> <span v-show="!DATA.isEdit"> <span>{{DATA.name}}</span> </span> <span class="tree-btn" v-show="!DATA.isEdit"> <i class="el-icon-plus" @click.stop="nodeAdd(STORE,DATA,NODE)"></i> <i class="el-icon-edit" @click.stop="nodeEdit(STORE,DATA,NODE)"></i> <i class="el-icon-delete" @click.stop="nodeDel(STORE,DATA,NODE)"></i> </span> </span> </template>
5.增
新增節(jié)點(diǎn) =》添加一條數(shù)據(jù)
- 新增的同時(shí)展開(kāi)父節(jié)點(diǎn)
- 是否考慮無(wú)限新增
//el-tree component handleAdd(s,d,n){//增加節(jié)點(diǎn) console.log(s,d,n) if(n.level >=6){ this.$message.error("最多只支持五級(jí)!") return false; } //添加數(shù)據(jù) d.children.push({ id: ++this.maxexpandId, name: '新增節(jié)點(diǎn)', pid: d.id, isEdit: false, children: [] }); //展開(kāi)節(jié)點(diǎn) if(!n.expanded){ n.expanded = true; } }
新增節(jié)點(diǎn)字體加粗 =》給節(jié)點(diǎn)添加一個(gè)class =》 如何判斷是否新增?
我們有一個(gè)參數(shù)maxexpandId
給tree_render
添加一個(gè)prop
:
//el-tree component renderContent(h,{node,data,store}){//加載節(jié)點(diǎn) let that = this; return h(TreeRender,{ props: { ... maxexpandId: that.non_maxexpandId }, on: {...} }); }
根據(jù)id判斷:
//tree_render component props: ['NODE', 'DATA', 'STORE', 'maxexpandId']
<!-- tree_render component --> <span v-show="!DATA.isEdit" :class="[DATA.id > maxexpandId ? 'tree-new tree-label' : 'tree-label']" :ref="'treeLabel'+DATA.id"> <span>{{DATA.name}}</span> </span> .tree-expand .tree-label.tree-new{ font-weight:600; }
6.刪
跟新增同義:刪除節(jié)點(diǎn) =》刪除一條數(shù)據(jù)
- 新增節(jié)點(diǎn)直接刪除
- 已有節(jié)點(diǎn)需提示再刪除
- 已有子級(jí)節(jié)點(diǎn)不能刪除
handleDelete(s,d,n){//刪除節(jié)點(diǎn) console.log(s,d,n) let that = this; //有子級(jí)不刪除 if(d.children && d.children.length !== 0){ this.$message.error("此節(jié)點(diǎn)有子級(jí),不可刪除!") return false; }else{ //刪除操作 let delNode = () => { let list = n.parent.data.children || n.parent.data, //節(jié)點(diǎn)同級(jí)數(shù)據(jù),頂級(jí)節(jié)點(diǎn)時(shí)無(wú)children _index = 99999;//要?jiǎng)h除的index list.map((c,i) => { if(d.id == c.id){ _index = i; } }) let k = list.splice(_index,1); //console.log(_index,k) this.$message.success("刪除成功!") } let isDel = () => { that.$confirm("是否刪除此節(jié)點(diǎn)?","提示",{ confirmButtonText: "確認(rèn)", cancelButtonText: "取消", type: "warning" }).then(() => { delNode()//此處可通過(guò)ajax做刪除操作 }).catch(() => { return false; }) } //新增節(jié)點(diǎn)直接刪除,否則要通過(guò)請(qǐng)求數(shù)據(jù)刪除 d.id > this.non_maxexpandId ? delNode() : isDel() } }
7.拓展
還有一些特別的需求,例如:
1、點(diǎn)擊高亮的時(shí)候顯示icon
.expand-tree .is-current>.el-tree-node__content .tree-btn, .expand-tree .el-tree-node__content:hover .tree-btn{ display: inline-block; }
2、添加頂級(jí)節(jié)點(diǎn)
添加按鈕:
<!-- el-tree component --> <el-button @click="handleAddTop">添加頂級(jí)節(jié)點(diǎn)</el-button>
添加methods:
//el-tree component methods: { handleAddTop(){ this.setTree.push({ id: ++this.maxexpandId, name: '新增節(jié)點(diǎn)', pid: '', isEdit: false, children: [] }) } }
3、默認(rèn)展開(kāi)樹(shù)形第一級(jí)
//el-tree component mounted(){ this.initExpand() }, methods: { initExpand(){ //isLoadingTree用意也是在此 this.setTree.map((a) => { this.defaultExpandKeys.push(a.id) }); this.isLoadingTree = true; }, }
8.github
還有些具體的樣式都放在github了
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 不依任何賴第三方,單純用vue實(shí)現(xiàn)Tree 樹(shù)形控件的案例
- Vue+Element UI 樹(shù)形控件整合下拉功能菜單(tree + dropdown +input)
- 詳解vue-element Tree樹(shù)形控件填坑路
- vue elementUI tree樹(shù)形控件獲取父節(jié)點(diǎn)ID的實(shí)例
- vue.js element-ui tree樹(shù)形控件改iview的方法
- 解決ant design vue中樹(shù)形控件defaultExpandAll設(shè)置無(wú)效的問(wèn)題
- vue遞歸組件實(shí)戰(zhàn)之簡(jiǎn)單樹(shù)形控件實(shí)例代碼
- vue用遞歸組件寫(xiě)樹(shù)形控件的實(shí)例代碼
- vue+iview使用樹(shù)形控件的具體使用
- vue樹(shù)形控件tree的使用方法
相關(guān)文章
Vue報(bào)錯(cuò):Uncaught TypeError: Cannot assign to read only propert
這篇文章主要給大家介紹了關(guān)于Vue報(bào)錯(cuò):Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>' 的解決方法,文中介紹的非常詳細(xì),需要的朋友們下面來(lái)一起看看吧。2017-06-06el-form的model、prop屬性和表單校驗(yàn)等使用
本文主要介紹了el-form的model、prop屬性和表單校驗(yàn)等使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08vue3?+?elementPlus?reset重置表單問(wèn)題
這篇文章主要介紹了vue3?+?elementPlus?reset重置表單問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05前端JS也可以連點(diǎn)成線詳解(Vue中運(yùn)用AntVG6)
這篇文章主要給大家介紹了關(guān)于前端JS連點(diǎn)成線(Vue中運(yùn)用?AntVG6)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-01-01當(dāng)啟動(dòng)vue項(xiàng)目安裝依賴時(shí)報(bào)錯(cuò)的解決方案
這篇文章主要介紹了當(dāng)啟動(dòng)vue項(xiàng)目安裝依賴時(shí)報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04Vue中select下拉框的默認(rèn)選中項(xiàng)的三種情況解讀
這篇文章主要介紹了Vue中select下拉框的默認(rèn)選中項(xiàng)的三種情況解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05vue2和vue3的v-if與v-for優(yōu)先級(jí)對(duì)比學(xué)習(xí)
這篇文章主要介紹了vue2和vue3的v-if與v-for優(yōu)先級(jí)對(duì)比學(xué)習(xí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10