一、Vue鼠标右键自定义菜单
在 Vue 中,我们可以使用 `v-contextmenu` 指令来绑定右键菜单事件。
这个指令接受一个方法名,这个方法会在右键菜单被触发时被调用。
先来看一个简单的例子,在下面的代码中,我们定义了一个右键菜单,并在 `showMenu` 方法中控制菜单的显示和隐藏。
右键点击这里
- 菜单项1
- 菜单项2
- 菜单项3
<script>
export default {
data() {
return {
show: false
}
},
methods: {
showMenu(e) {
e.preventDefault();
this.show = true;
document.addEventListener("click", () => {
this.show = false;
}, { once: true });
}
}
}
</script>
二、Vue定义自定义鼠标右键
Vue 自带的指令只能帮我们绑定右键菜单事件,但是这些事件缺乏我们自定义菜单样式和内容的能力。
我们可以使用 `window.oncontextmenu` 监听右键菜单事件,并自定义菜单的样式和内容。
下面是一个自定义右键菜单的例子,我们可以通过 `v-html` 将菜单项渲染到菜单中。
右键点击这里
<script>
export default {
data() {
return {
left: 0,
top: 0,
menu: ""
}
},
methods: {
showMenu(e) {
e.preventDefault();
// 自定义菜单内容
this.menu = `
<li>菜单项1</li>
<li>菜单项2</li>
<li>菜单项3</li>
`;
// 自定义菜单样式
this.left = e.clientX;
this.top = e.clientY;
// 在下一帧中关闭菜单
this.$nextTick(() => {
document.addEventListener("click", () => {
this.menu = "";
}, { once: true });
});
}
}
}
</script>
三、Vue实现多级右键菜单
有时候我们需要实现一个多级的右键菜单,下面是一个简单的例子。
首先,我们需要定义一个菜单项组件,并使用 `v-for` 渲染出菜单项列表。
当鼠标进入菜单项时,我们使用 `setTimeout` 延迟 300 毫秒显示下一级菜单,当鼠标移出菜单项时,隐藏下一级菜单。
右键点击这里
<script>
import MenuItem from "./MenuItem";
export default {
components: { MenuItem },
data() {
return {
left: 0,
top: 0,
menu: [
{
name: "菜单项1",
children: [
{
name: "子菜单1-1"
},
{
name: "子菜单1-2"
}
]
},
{
name: "菜单项2"
},
{
name: "菜单项3",
children: [
{
name: "子菜单3-1",
children: [
{
name: "子菜单3-1-1"
},
{
name: "子菜单3-1-2"
}
]
}
]
}
]
}
},
methods: {
showMenu(e) {
e.preventDefault();
this.left = e.clientX;
this.top = e.clientY;
}
}
}
</script>
下面是菜单项组件的代码,当鼠标进入菜单项时,我们设置 `showSubmenu` 为 `true` 显示下一级菜单;当鼠标移出菜单项时,我们设置 `showSubmenu` 为 `false` 隐藏下一级菜单。
{{ item.name }}
<script>
import MenuItem from "./MenuItem";
export default {
components: { MenuItem },
props: {
item: {
type: Object,
required: true
}
},
data() {
return {
showSubmenu: false
}
},
computed: {
hasChildren() {
return Array.isArray(this.item.children) && this.item.children.length > 0;
}
},
methods: {
enter() {
if (this.hasChildren) {
setTimeout(() => {
this.showSubmenu = true;
}, 300);
}
},
leave() {
if (this.hasChildren) {
this.showSubmenu = false;
}
}
}
}
</script>