VUE饿了么树形控件添加增删改功能的示例代码
本文介绍了vue饿了么树形控件添加增删改功能的示例代码,分享给大家,具体如下:
element-ui树形控件:地址
在原文档中有个案例是有新增和删除功能,但是后来发现其修改的数据并不能直接影响到树形数据,所以采用了 render-content 的api重新写了个组件。
写个开发的步骤,所以文章比较长emmm
大致效果如图:
1.省市api
在网上复制了个省市的list,有两个属性是新增的
- isedit :控制编辑状态
- maxexpandid :为现下id的最大值
export default{ maxexpandid: 95, treelist: [{ id: 1, name: "北京市", prosort: 1, remark: "直辖市", pid: '', isedit: false, children: [{ id: 35, name: "朝阳区", pid: 1, remark: '', isedit: false, children: [] }] }{...}] }
2.el-tree component基本
咱们一步步来,先写个饿了么的组件
<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 :为了点击时节点高亮 * expand-on-click-node : 只能箭头控制树形的展开收缩 * render-content : 节点渲染方式 * default-expanded-keys :默认展开节点 -->
同时引入api和节点渲染的组件
import treerender from '@/components/tree_render' import api from '@/resource/api'
然后搭建好基础
data(){ return{ maxexpandid: api.maxexpandid,//新增节点开始id non_maxexpandid: api.maxexpandid,//新增节点开始id(不更改) isloadingtree: false,//是否加载节点树 settree: api.treelist,//节点树数据 defaultprops: { children: 'children', label: 'name' }, defaultexpandkeys: [],//默认展开节点列表 } },
添加个渲染的method
methods: { rendercontent(h,{node,data,store}){ let that = this;//指向vue return h(treerender,{ props: { data: data,//节点数据 node: node,//节点内容 store: store,//完整树形内容 }, 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){//增加节点 console.log(s,d,n) }, handleedit(s,d,n){//编辑节点 console.log(s,d,n) }, handledelete(s,d,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>
添加好几个按钮(element-ui自带icon:地址)对应的方法:
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来切换input和span的显示状态,首先加个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>
编辑的时候按钮同时消失,那么什么时候编辑完成呢?
- 编辑完按enter键=》监听input的enter输入
- 点击其他节点=》input失焦-blur=》编辑时自动聚焦-focus
- 点击当前节点范围
当以上三点发生一项,节点对应的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>
后来发现第一次编辑时能让input聚焦,点击第二个input就不起作用了,加了autofocus属性也同样如此。所以我们要在点击编辑icon的时候,用原生的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、当前节点点击
采用el-tree已有的api——node-click
<!-- el-tree component --> <el-tree @node-click="handlenodeclick"></el-tree>
添加methods:
//el-tree component methods: { handlenodeclick(d,n,s){//点击节点 d.isedit = false;//放弃编辑状态 } }
问题来了,如果在编辑状态下点击此节点也同样会影响input,这就无法进入编辑,所以要阻止input事件冒泡:
<!-- tree_render component --> <el-input @click.stop.native="nodeeditfocus"></el-input>
添加methods:
//tree_render component methods: { nodeeditfocus(){} }
4、v-show代替v-if
这里有个新的问题,当用户经常编辑修改,v-if模板的开销更高,所以改用v-show。而后者不支持template模板,所以要适当调整一下位置:
<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.增
新增节点 =》添加一条数据
- 新增的同时展开父节点
- 是否考虑无限新增
//el-tree component handleadd(s,d,n){//增加节点 console.log(s,d,n) if(n.level >=6){ this.$message.error("最多只支持五级!") return false; } //添加数据 d.children.push({ id: ++this.maxexpandid, name: '新增节点', pid: d.id, isedit: false, children: [] }); //展开节点 if(!n.expanded){ n.expanded = true; } }
新增节点字体加粗 =》给节点添加一个class =》 如何判断是否新增?
我们有一个参数maxexpandid
给tree_render
添加一个prop
:
//el-tree component rendercontent(h,{node,data,store}){//加载节点 let that = this; return h(treerender,{ props: { ... maxexpandid: that.non_maxexpandid }, on: {...} }); }
根据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.删
跟新增同义:删除节点 =》删除一条数据
- 新增节点直接删除
- 已有节点需提示再删除
- 已有子级节点不能删除
handledelete(s,d,n){//删除节点 console.log(s,d,n) let that = this; //有子级不删除 if(d.children && d.children.length !== 0){ this.$message.error("此节点有子级,不可删除!") return false; }else{ //删除操作 let delnode = () => { let list = n.parent.data.children || n.parent.data, //节点同级数据,*节点时无children _index = 99999;//要删除的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("是否删除此节点?","提示",{ confirmbuttontext: "确认", cancelbuttontext: "取消", type: "warning" }).then(() => { delnode()//此处可通过ajax做删除操作 }).catch(() => { return false; }) } //新增节点直接删除,否则要通过请求数据删除 d.id > this.non_maxexpandid ? delnode() : isdel() } }
7.拓展
还有一些特别的需求,例如:
1、点击高亮的时候显示icon
.expand-tree .is-current>.el-tree-node__content .tree-btn, .expand-tree .el-tree-node__content:hover .tree-btn{ display: inline-block; }
2、添加*节点
添加按钮:
<!-- el-tree component --> <el-button @click="handleaddtop">添加*节点</el-button>
添加methods:
//el-tree component methods: { handleaddtop(){ this.settree.push({ id: ++this.maxexpandid, name: '新增节点', pid: '', isedit: false, children: [] }) } }
3、默认展开树形第一级
//el-tree component mounted(){ this.initexpand() }, methods: { initexpand(){ //isloadingtree用意也是在此 this.settree.map((a) => { this.defaultexpandkeys.push(a.id) }); this.isloadingtree = true; }, }
8.github
还有些具体的样式都放在了
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。