element组件的官方文档:https://element.eleme.io/#/zh-CN/component/tree
完整代码在最下方。
1.做一个右键点击弹出的div,可供增删改并分别注册点击事件:
同级增加
子级增加
删除节点
修改节点
2.树形控件页面拉到最下面:阅读Events表格
:data="treeData"
node-key="id"
default-expand-all // 默认展开所有节点
@node-contextmenu="rightClick"
ref="tree">
首先我们给这棵树注册右击事件,弹出可以选择增删改的div,同时将点击的节点保存起来。
第一层节点包含:同级添加、子级添加、删除节点、修改节点
其余叶子节点包含:子级添加、删除节点、修改节点
在标签中添加: @node-contextmenu="rightClick" ,该事件包含4个参数,如图所示:
rightClick (MouseEvent, object, Node, element) { // event、object该节点所对应的对象、节点对应的 Node、节点组件本身
this.currentData = object // 定义变量接收该节点所对应的对象
this.currentNode = Node // 定义变量接收该节点对应的 Node
if (Node.level ===1) { // 判断节点是否为第一层节点
this.firstLevel =true // 是的话显示同级添加选项
}else {
this.firstLevel =false // 否则视为叶子节点不添加同级选项
}
this.menuVisible =true //显示增删改的div
document.addEventListener('click',this.foo) // 监听事件鼠标点击事件,若点击则隐藏菜单
this.$refs.card.$el.style.left =event.clientX +40 +'px'
this.$refs.card.$el.style.top =event.clientY +10 +'px' // 以上两句话将菜单显示在鼠标点击旁边定位
},
foo () {
this.menuVisible =false
// 要及时关掉监听,不关掉的是一个坑,不信你试试,虽然前台显示的时候没有啥毛病,加一个alert你就知道了
document.removeEventListener('click',this.foo)
},
3.点击-同级添加
addSameLevelNode () {
let id =Math.ceil(Math.random() *100) //随机产生id(至于id很小概率重复的问题,我没解决。)
var data = {id:id,label:'新增节点'}
this.$refs.tree.append(data,this.currentNode.parent) // 同级添加的parent,就是当前的点击的parent
},
4.点击-子级添加
addChildNode () {
console.log(this.currentData)
console.log(this.currentNode)
if (this.currentNode.level >=3) { // 判断当前节点的level,若是第三层,弹出提示
this.$message.error('最多只支持三级!')
return false
}
let id =Math.ceil(Math.random() *100)
var data = {id:id,label:'新增节点'}
this.$refs.tree.append(data,this.currentNode) // 这边和同级添加类似哒
},
5.点击-删除节点
deleteNode () { // 这个我之所以没有传data ,是因刚刚右击的节点数据我都保存到变量中了
this.$refs.tree.remove(this.currentNode)
},
6.点击-修改节点名
我做的效果如图:先在
// 这个isEdit是我数据中就有的,默认都是false。isEdit是false取反是true是span标签显示,反之隐藏。(但是我添加节点没有这个属性不知道为啥可以编辑。。。当然前面可以自己 加个isEdit:false试试哈)
// 这个:class我没用到可以去掉
{{node.label}}
// isEdit是true,上面span标签隐藏,input标签显示,呈现编辑的状态
v-model="data.label" // input标签内容保存在data.label上,从而改变数据
:ref="'slotTreeInput'+data.id"
@blur.stop="NodeBlur(node,data)"
@keydown.native.enter="NodeBlur(node,data)"> // 失去焦点或enter键表明编辑结束触发的事件
调用的函数
NodeBlur (Node, data) {
console.log(Node, data)
if (data.isEdit) {
this.$set(data,'isEdit',false) // 先把isEdit置为false
console.log(data.isEdit)
this.$nextTick(() => { // 这个我不太懂,后续查查。。。
this.$refs['slotTreeInput' + data.id].$refs.input.focus()
})
}
},
7.查找-我是做的所有节点查找
placeholder="输入关键字进行过滤"
v-model="filterText" // 这个记得在data中定义
class="search">
// 函数
filterNode (value, data) {
if (!value)return true
return data.label.indexOf(value) !== -1
},
watch: {
filterText (val) {
this.$refs.tree.filter(val)
}
},
8.节点的拖拽
根据上图,我们给el-tree注册这些事件:
:data="treeData"
node-key="id"
default-expand-all
@node-click="handleLeftclick"
@node-drag-start="handleDragStart"
@node-drag-enter="handleDragEnter"
@node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver"
@node-drag-end="handleDragEnd"
@node-drop="handleDrop"
@node-contextmenu="rightClick"
:filter-node-method="filterNode"
draggable
:allow-drop="allowDrop"
:allow-drag="allowDrag"
ref="tree">
对应的事件:
handleDragEnter (draggingNode, dropNode, ev) {
console.log('tree drag enter: ', dropNode.label)
},
handleDragLeave (draggingNode, dropNode, ev) {
console.log('tree drag leave: ', dropNode.label)
},
handleDragOver (draggingNode, dropNode, ev) {
console.log('tree drag over: ', dropNode.label)
},
handleDragEnd (draggingNode, dropNode, dropType, ev) {
console.log('tree drag end: ', dropNode && dropNode.label, dropType)
},
handleDrop (draggingNode, dropNode, dropType, ev) {
console.log('tree drop: ', dropNode.label, dropType)
},
9.完整代码
placeholder="输入关键字进行过滤"
v-model="filterText"
class="search">
:data="treeData"
node-key="id"
default-expand-all
@node-click="handleLeftclick"
@node-drag-start="handleDragStart"
@node-drag-enter="handleDragEnter"
@node-drag-leave="handleDragLeave"
@node-drag-over="handleDragOver"
@node-drag-end="handleDragEnd"
@node-drop="handleDrop"
@node-contextmenu="rightClick"
:filter-node-method="filterNode"
draggable
:allow-drop="allowDrop"
:allow-drag="allowDrag"
ref="tree">
{{node.label}}
v-model="data.label"
:ref="'slotTreeInput'+data.id"
@blur.stop="NodeBlur(node,data)"
@keydown.native.enter="NodeBlur(node,data)">
同级增加
子级增加
删除节点
修改节点
import '../mock/mockfile.js'
import axios from 'axios'
export default {
name:'processManagement',
data () {
return {
eleId:'',
isShow:false,
currentData:'',
currentNode:'',
menuVisible:false,
firstLevel:false,
filterText:'',
maxexpandId:4,
treeData: [{
id:1,
label:'一级 1',
isEdit:false,
children: [{
id:4,
label:'二级 1-1',
isEdit:false,
children: [{
id:9,
label:'三级 1-1-1',
isEdit:false
}, {
id:10,
label:'三级 1-1-2',
isEdit:false
}]
}]
}, {
id:2,
label:'一级 2',
isEdit:false,
children: [{
id:5,
label:'二级 2-1',
isEdit:false
}, {
id:6,
label:'二级 2-2',
isEdit:false
}]
}, {
id:3,
label:'一级 3',
isEdit:false,
children: [{
id:7,
label:'二级 3-1',
isEdit:false
}, {
id:8,
label:'二级 3-2',
isEdit:false,
children: [{
id:11,
label:'三级 3-2-1',
isEdit:false
}, {
id:12,
label:'三级 3-2-2',
isEdit:false
}, {
id:13,
label:'三级 3-2-3',
isEdit:false
}]
}]
}],
defaultProps: {
children:'children',
label:'label'
}
}
},
methods: {
test () {
axios.get('http://test.cn')
.then(response => {
this.isShow = response.data.operations[0].pubResource.isVisiable
console.log(response.data.operations[0].pubResource)
this.eleId = response.data.operations[0].pubResource.elementId
})
},
NodeBlur (Node, data) {
debugger
console.log(Node, data)
if (data.label.length ===0) {
this.$message.error('菜单名不可为空!')
return false
}else {
if (data.isEdit) {
this.$set(data,'isEdit',false)
console.log(data.isEdit)
}
this.$nextTick(() => {
this.$refs['slotTreeInput' + data.id].$refs.input.focus()
})
}
},
// 查询
filterNode (value, data) {
if (!value)return true
return data.label.indexOf(value) !== -1
},
handleDragStart (node, ev) {
console.log('drag start', node)
},
handleDragEnter (draggingNode, dropNode, ev) {
console.log('tree drag enter: ', dropNode.label)
},
handleDragLeave (draggingNode, dropNode, ev) {
console.log('tree drag leave: ', dropNode.label)
},
handleDragOver (draggingNode, dropNode, ev) {
console.log('tree drag over: ', dropNode.label)
},
handleDragEnd (draggingNode, dropNode, dropType, ev) {
console.log('tree drag end: ', dropNode && dropNode.label, dropType)
},
handleDrop (draggingNode, dropNode, dropType, ev) {
console.log('tree drop: ', dropNode.label, dropType)
},
allowDrop (draggingNode, dropNode, type) {
if (dropNode.data.label ==='二级 3-1') {
return type !=='inner'
}else {
return true
}
},
allowDrag (draggingNode) {
return draggingNode.data.label.indexOf('三级 3-2-2') === -1
},
// 鼠标右击事件
rightClick (MouseEvent, object, Node, element) {
debugger
this.currentData = object
this.currentNode = Node
if (Node.level ===1) {
this.firstLevel =true
}else {
this.firstLevel =false
}
this.menuVisible =true
// let menu = document.querySelector('#card')
// /* 菜单定位基于鼠标点击位置 */
// menu.style.left = event.clientX + 'px'
// menu.style.top = event.clientY + 'px'
document.addEventListener('click',this.foo)
this.$refs.card.$el.style.left =event.clientX +40 +'px'
this.$refs.card.$el.style.top =event.clientY +10 +'px'
},
// 鼠标左击事件
handleLeftclick (data, node) {
this.foo()
},
// 取消鼠标监听事件 菜单栏
foo () {
this.menuVisible =false
// 要及时关掉监听,不关掉的是一个坑,不信你试试,虽然前台显示的时候没有啥毛病,加一个alert你就知道了
document.removeEventListener('click',this.foo)
},
// 增加同级节点事件
addSameLevelNode () {
let id =Math.ceil(Math.random() *100)
var data = {id:id,label:'新增节点'}
this.$refs.tree.append(data,this.currentNode.parent)
},
// 增加子级节点事件
addChildNode () {
console.log(this.currentData)
console.log(this.currentNode)
if (this.currentNode.level >=3) {
this.$message.error('最多只支持三级!')
return false
}
let id =Math.ceil(Math.random() *100)
var data = {id:id,label:'新增节点'}
this.$refs.tree.append(data,this.currentNode)
},
// 删除节点
deleteNode () {
this.$refs.tree.remove(this.currentNode)
},
// 编辑节点
editNode () {
debugger
if (!this.currentData.isEdit) {
this.$set(this.currentData,'isEdit',true)
}
}
},
watch: {
filterText (val) {
this.$refs.tree.filter(val)
}
},
mounted () {
this.test()
}
}
/*.lalala {*/
/*position: relative;*/
/*}*/
.text {
font-size:14px;
}
.el-tree{
width:20%;
margin-top:10px;
}
.search{
width:20%;
}
.item {
padding:18px 0;
}
.add{
cursor:pointer;
margin-top:10px;
}
.delete{
margin:10px 0;
cursor:pointer;
}
.edit{
margin-bottom:10px;
cursor:pointer;
}
.search {
cursor:pointer;
}
.box-card {
width:120px;
position:absolute;
z-index:1000;
}