参考链接:
Element 组件之 右键鼠标 自定义菜单Vue+ElementUI实现给Tab页添加鼠标右键菜单栏
Element tree组件之 自定义菜单
基于element tree组件。效果图如下:
1、 基于element组件 tree组件
2、 右键任何位置 基于鼠标位置跳转菜单
3、 类比于window鼠标右键一样的效果
4、 为什么基于elemet的右键菜单,因为,人家给封装好了 右键点击鼠标事件,以及点击鼠标右键事件时杀掉了系统的右击事件
链接地址:Element tree
基本思路:
给tree树绑定鼠标右键点击出发的事件 rightClick。当右击时出发函数,在函数中实现弹出右侧菜单栏事件 ,并且记录正在操作的 Node 。
这里使用的是element ui ,其帮我们关闭了默认的菜单弹出。
原声js
① 原生js方式实现时,要注意阻止弹出浏览器默认的菜单栏,即使用 e.preventDefault();
② 若跨组件了,则可以使用store的方式来对值进行存储和事件响应。
<style type="text/css">
.menu__item {
display: block;
line-height: 20px;
text-align: center;
margin-top: 10px;
}
.menu {
height: 100px;
width: 100px;
position: absolute;
border-radius: 10px;
border: 1px solid #999999;
background-color: #f4f4f4;
}
li:hover {
background-color: #1790ff;
color: white;
}
</style>
</head>
<body>
<div id="app">
<!--
:expand-on-click-node="false" // 只能点击箭头才能显示子级列表
@node-contextmenu="rightClick" // 鼠标右键触发的事件
:highlight-current="true" // 高亮
@node-click="handleNodeClick"> // 鼠标点击触发的事件
-->
<el-tree
:data="data"
:props="defaultProps"
node-key="id"
:expand-on-click-node="false"
@node-contextmenu="rightClick"
:highlight-current="true"
@node-click="handleNodeClick"
>
</el-tree>
<!--鼠标右键菜单栏,其实就是添加一个基于鼠标位置的模态框而已 -->
<div v-show="menuVisible">
<ul id="menu" class="menu">
<li class="menu__item" @click="append(clickNode)">平级添加</li>
<li class="menu__item" @click="addCard(clickNode)">下级添加</li>
<li class="menu__item" @click="remove(clickNode)">删除</li>
</ul>
</div>
</div>
</body>
<script type="application/javascript">
new Vue({
el: '#app',
data: {
menuVisible:false,
data: [{
id: 1,
label: '一级 1',
children: [{
id: 4,
label: '二级 1-1',
children: [{
id: 9,
label: '三级 1-1-1'
}, {
id: 10,
label: '三级 1-1-2'
}]
}]
}, {
id: 2,
label: '一级 2',
children: [{
id: 5,
label: '二级 2-1'
}, {
id: 6,
label: '二级 2-2'
}]
}, {
id: 3,
label: '一级 3',
children: [{
id: 7,
label: '二级 3-1'
}, {
id: 8,
label: '二级 3-2',
children: [{
id: 11,
label: '三级 3-2-1'
}, {
id: 12,
label: '三级 3-2-2'
}, {
id: 13,
label: '三级 3-2-3'
}]
}]
}],
defaultProps: {
children: 'children',
label: 'label'
},
clickNode : '',
id :14
},
defaultProps: {
children: 'children',
label: 'label'
},
methods: {
handleNodeClick (data) {
console.log(data);
},
rightClick (MouseEvent, object, Node, element) { // 鼠标右击触发事件
this.menuVisible = false // 先把模态框关死,目的是 第二次或者第n次右键鼠标的时候 它默认的是true
this.menuVisible = true // 显示模态窗口,跳出自定义菜单栏
var menu = document.querySelector('#menu')
menu.style.left = MouseEvent.clientX + 5 + 'px' // MouseEvent.clientX获取鼠标点击的坐标,在该处新增加的menu填充的位置
menu.style.top = MouseEvent.clientY - 10 + 'px'
document.addEventListener('click', this.foo) // 给整个document添加监听鼠标事件,点击任何位置执行foo方法
console.log('右键被点击的event:', MouseEvent)
console.log('右键被点击的object:', object)
console.log('右键被点击的value:', Node)
console.log('右键被点击的element:', element)
console.log('鼠标点击了树形结构图')
this.clickNode = Node //存储待操作的节点或删除、或在该层或子层添加节点
// alert(Node.level +":"+Node.label)
},
foo () { // 取消鼠标监听事件 菜单栏
this.menuVisible = false
document.removeEventListener('click', this.foo) // 要及时关掉监听,不关掉的是一个坑,不信你试试,虽然前台显示的时候没有啥毛病,加一个alert你就知道了
},
addCard (data) {
const newChild = { id: this.id++, label: 'testtest', children: [] };
//debugger
if (!data.data.children) {
this.$set(data.data, 'children', []);// 最后一层节点添加下一层节点,先给其添加children属性
}
data.data.children.push(newChild);
},
remove (data) {
//const newChild = { id: this.id++, label: 'testtest', children: [] };
//debugger
if (data.parent.data.children) {
return data.parent.data.children.pop(data.data) // 第一层以外的节点,父节点有children,从其父节点的children踢去该节点
}
data.parent.data.pop(data.data) // 第一层节点 ,父节点没有children从其父节点的children踢去该节点
},
append(data) {
const newChild = { id: this.id++, label: 'testtest', children: [] };
//debugger
if (!data.parent.data.children) {
return data.parent.data.push(newChild) // 第一层节点添加兄弟层级菜单栏
}
data.parent.data.children.push(newChild) // 第二层节点添加兄弟层级菜单栏
},
}
})
</script>
附注: 原生js
① 原生js方式实现时,要注意阻止弹出浏览器默认的菜单栏,即使用 e.preventDefault();
② 若跨组件了,则可以使用store的方式来对值进行存储和事件
/*
右击事件
*/
openContextMenu(e) {
e.preventDefault(); //防止默认菜单弹出
let obj = e.srcElement ? e.srcElement : e.target;
if (obj.id) {
let currentContextTabId = obj.id.split("-")[1];
let curIndex = 0;
for(;curIndex<this.editableTabs.length;++curIndex){
if(this.editableTabs[curIndex].title == currentContextTabId){
break;
}
}
if(curIndex<=0){
this.isDisabledCloseLeftBtnFlag = true
this.isDisabledCloseRightBtnFlag = false
}else if(curIndex >= this.editableTabs.length-1){
this.isDisabledCloseLeftBtnFlag = false
this.isDisabledCloseRightBtnFlag = true
}else{
this.isDisabledCloseLeftBtnFlag = false
this.isDisabledCloseRightBtnFlag = false
}
this.contextMenuVisible = true;
this.$store.commit("saveCurContextTabId", currentContextTabId);
this.left = e.clientX;
this.top = e.clientY + 10;
}
},