在饿了么原文档中有个案例是有新增和删除功能,但是后来发现其修改的数据并不能直接影响到树形数据,所以采用了 render-content
的API重新写了个组件。
写个开发的步骤,所以文章比较长emmm
element-ui树形控件:地址
大致效果如图:
1.省市API
在网上复制了个省市的list,有两个属性是新增的
isEdit
:控制编辑状态maxexpandId
:为现下id的最大值
1 | export default{ |
2.el-tree Component基本
咱们一步步来,先写个饿了么的组件
1 | <template> |
同时引入API和节点渲染的组件
1 | import TreeRender from '@/components/tree_render' |
然后搭建好基础
1 | data(){ |
添加个渲染的method
1 | methods: { |
3.tree_render Component基本
渲染组件:
1 | <template> |
添加好几个按钮(element-ui自带icon:地址)对应的方法:
1 | export default{ |
4.改
我们用isEdit
来切换input
和span
的显示状态,首先加个input:
1 | <!-- tree_render component --> |
编辑的时候按钮同时消失,那么什么时候编辑完成呢?
- 编辑完按enter键=》监听input的enter输入
- 点击其他节点=》input失焦-
blur
=》编辑时自动聚焦-focus
- 点击当前节点范围
当以上三点发生一项,节点对应的data都要isEdit = false;
enter键
1
2<!-- tree_render component -->
<el-input @keyup.enter.native="nodeEditPass(STORE,DATA,NODE)"></el-input>添加方法:
1
2
3
4
5
6//tree_render component
methods: {
nodeEditPass(s,d,n){
d.isEdit = false;
}
}focus or blur
1
2<!-- tree_render component -->
<el-input @blur="nodeEditPass(STORE,DATA,NODE)"></el-input>后来发现第一次编辑时能让
input
聚焦,点击第二个input
就不起作用了,加了autofocus
属性也同样如此。所以我们要在点击编辑icon
的时候,用原生的input autofocus
。
修改方法:1
2
3
4
5
6
7
8//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)
}当前节点点击
采用el-tree
已有的API——node-click
1
2<!-- el-tree component -->
<el-tree @node-click="handleNodeClick"></el-tree>添加methods:
1
2
3
4
5
6//el-tree component
methods: {
handleNodeClick(d,n,s){//点击节点
d.isEdit = false;//放弃编辑状态
}
}问题来了,如果在编辑状态下点击此节点也同样会影响input,这就无法进入编辑,所以要阻止input事件冒泡:
1
2<!-- tree_render component -->
<el-input @click.stop.native="nodeEditFocus"></el-input>添加methods:
1
2
3
4//tree_render component
methods: {
nodeEditFocus(){}
}v-show
代替v-if
这里有个新的问题,当用户经常编辑修改,
v-if
模板的开销更高,所以改用v-show。而后者不支持template模板,所以要适当调整一下位置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<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.增
新增节点 =》添加一条数据
- 新增的同时展开父节点
- 是否考虑无限新增
1 | //el-tree component |
新增节点字体加粗 =》给节点添加一个class =》 如何判断是否新增?
我们有一个参数maxexpandId
给tree_render
添加一个prop
:
1 | //el-tree component |
根据id判断:
1 | //tree_render component |
1 | <!-- tree_render component --> |
1 | .tree-expand .tree-label.tree-new{ |
6.删
跟新增同义:删除节点 =》删除一条数据
- 新增节点直接删除
- 已有节点需提示再删除
- 已有子级节点不能删除
1 | handleDelete(s,d,n){//删除节点 |
7.拓展
还有一些特别的需求,例如:
点击高亮的时候显示icon
1
2
3
4.expand-tree .is-current>.el-tree-node__content .tree-btn,
.expand-tree .el-tree-node__content:hover .tree-btn{
display: inline-block;
}添加顶级节点
添加按钮:1
2<!-- el-tree component -->
<el-button @click="handleAddTop">添加顶级节点</el-button>添加methods:
1
2
3
4
5
6
7
8
9
10
11
12//el-tree component
methods: {
handleAddTop(){
this.setTree.push({
id: ++this.maxexpandId,
name: '新增节点',
pid: '',
isEdit: false,
children: []
})
}
}默认展开树形第一级
1
2
3
4
5
6
7
8
9
10
11
12
13//el-tree component
mounted(){
this.initExpand()
},
methods: {
initExpand(){
//isLoadingTree用意也是在此
this.setTree.map((a) => {
this.defaultExpandKeys.push(a.id)
});
this.isLoadingTree = true;
},
}
8.github
还有些具体的样式都放在github了
如有错漏,欢迎指正╰( ◕ ▽ ◕ )╯
扫描二维码,分享此文章