Vue3.0 自定义右键菜单,支持 Vite2.0,官网
Vue3.0 原生实现完全自定义右键菜单组件, 零依赖,可根据可视区域自动调节显示位置,可支持插槽完全重写每一项菜单
npm install vue3-menus
或
yarn add vue3-menus
<script src="https://unpkg.com/vue3-menus/dist/vue3-menus.umd.min.js">
CDN引入则不需要 app.use(Vue3Menus)
样例中使用的是
@ant-design/icons-vue
图标与@element-plus/icons
图标、图标可以使用html
代码传入、也可以通过插槽自定义图标
、也可以完全重写每一项菜单
// 全局注册组件、指令、方法
import { createApp } from 'vue';
import Menus from 'vue3-menus';
import App from './App.vue';
const app = createApp(App);
app.use(Menus);
app.mount('#app');
// 单个注册某个,以下三种方式均可在单个文件内使用
import { createApp } from 'vue';
import { directive, menusEvent, Vue3Menus } from 'vue3-menus';
import App from './App.vue';
const app = createApp(App);
app.component('vue3-menus', Vue3Menus); // 只注册组件
app.directive('menus', directive); // 只注册指令
app.config.globalProperties.$menusEvent = menusEvent; // 只绑定方法
app.mount('#app');
<template>
<div style="height: 98vh; width: 100%;" v-menus:left="menus">
<div class="div" v-menus:left="menus">指令方式打开菜单</div>
<div class="div" @click.stop @contextmenu="($event) => $menusEvent($event, menus)">事件方式打开菜单</div>
<div class="div" @click.stop @contextmenu="rightClick">组件方式打开菜单</div>
<vue3-menus :open="isOpen" :event="eventVal" :menus="menus.menus">
<template #icon="{menu, activeIndex, index}">{{activeIndex}}</template>
<template #label="{ menu, activeIndex, index }">插槽:{{ menu.label }}</template>
</vue3-menus>
</div>
</template>
<script>
import { defineComponent, nextTick, ref, shallowRef } from "vue";
import { SyncOutlined, WindowsOutlined, QrcodeOutlined } from '@ant-design/icons-vue';
import { Printer } from '@element-plus/icons'
export default defineComponent({
name: "App",
setup() {
const isOpen = ref(false);
const eventVal = ref({});
function rightClick(event) {
isOpen.value = false;
nextTick(() => {
eventVal.value = event;
isOpen.value = true;
})
event.preventDefault();
}
const menus = shallowRef({
menus: [
{
label: "返回(B)",
tip: 'Alt+向左箭头',
click: () => {
window.history.back(-1);
}
},
{
label: "点击不关闭菜单",
tip: '不关闭菜单',
click: () => {
return false;
}
},
{
label: "前进(F)",
tip: 'Alt+向右箭头',
disabled: true
},
{
label: "重新加载(R)",
tip: 'Ctrl+R',
click: () => location.reload(),
divided: true
},
{
label: "另存为(A)...",
tip: 'Ctrl+S'
},
{
label: "打印(P)...",
tip: 'Ctrl+P',
click: () => window.print(),
},
{
label: "投射(C)...",
divided: true
},
{
label: '发送到你的设备',
children: [
{
label: 'iPhone',
},
{
label: 'iPad'
},
{
label: 'Windows 11'
}
]
},
{
label: "为此页面创建二维码",
divided: true,
},
{
label: "使用网页翻译(F)",
divided: true,
children: [
{ label: "翻译成繁体中文" },
{ label: "翻译成繁体中文" },
{
label: "百度翻译", children: [
{ label: "翻译成繁体中文" },
{ label: "翻译成繁体中文" },]
},
{
label: "搜狗翻译", children: [
{ label: "翻译成繁体中文" },
{ label: "翻译成繁体中文" },
]
},
{
label: "有道翻译", children: [
{ label: "翻译成繁体中文" },
{ label: "翻译成繁体中文" },
]
},
]
},
{
label: "截取网页(R)"
},
{ label: "查看网页源代码(U)", tip: 'Ctrl+U' },
{ label: "检查(N)", tip: 'Ctrl+Shift+I' }
]
})
return { menus, isOpen, rightClick, eventVal }
},
});
</script>
.div {
display: inline-block;
background-color: aqua;
margin: 0 20px;
line-height: 200px;
padding: 0 20px;
height: 200px;
}
<template>
<div v-menus:left="menus">指令方式打开菜单</div>
</template>
<script>
import { defineComponent, shallowRef } from "vue";
import { directive } from 'vue3-menus';
export default defineComponent({
name: "App",
directives: {
menus: directive
},
setup() {
const menus = shallowRef({
menus: [
{
label: "返回(B)",
tip: 'Alt+向左箭头',
click: () => {
window.history.back(-1);
}
},
{
label: "点击不关闭菜单",
tip: '不关闭菜单',
click: () => {
return false;
}
}
]
})
return { menus }
},
});
</script>
<template>
<div class="div" @click.stop @contextmenu="rightClick">事件方式打开菜单</div>
</template>
<script>
import { defineComponent, shallowRef } from "vue";
import { menusEvent } from 'vue3-menus';
export default defineComponent({
name: "App",
setup() {
const menus = shallowRef({
menus: [
{
label: "返回(B)",
tip: 'Alt+向左箭头',
click: () => {
window.history.back(-1);
}
},
{
label: "点击不关闭菜单",
tip: '不关闭菜单',
click: () => {
return false;
}
}
]
});
function rightClick(event) {
menusEvent(event, menus.value);
event.preventDefault();
}
return { rightClick }
},
});
</script>
<template>
<div class="div" @click.stop @contextmenu="rightClick">组件方式打开菜单</div>
<vue3-menus v-model:open="isOpen" :event="eventVal" :menus="menus" hasIcon>
<template #icon="{menu, activeIndex, index}">{{activeIndex}}</template>
<template #label="{ menu, activeIndex, index}">插槽:{{ menu.label }}</template>
</vue3-menus>
</template>
<script>
import { defineComponent, nextTick, ref, shallowRef } from "vue";
import { Vue3Menus } from 'vue3-menus';
export default defineComponent({
name: "App",
components: {
Vue3Menus
},
setup() {
const isOpen = ref(false);
const eventVal = ref({});
function rightClick(event) {
isOpen.value = false;
nextTick(() => {
eventVal.value = event;
isOpen.value = true;
})
event.preventDefault();
}
const menus = shallowRef([
{
label: "返回(B)",
tip: 'Alt+向左箭头',
click: () => {
window.history.back(-1);
}
},
{
label: "点击不关闭菜单",
tip: '不关闭菜单',
click: () => {
return false;
}
}
]);
return { menus, isOpen, rightClick, eventVal }
},
});
</script>
属性 | 描述 | 类型 | 是否必填 | 默认值 |
---|---|---|---|---|
key | 菜单项键值 | string |
false |
— |
label | 菜单项名称 | string | (key?: string)=>string |
true |
— |
style | 每一项菜单的自定义样式 | object |
false |
{} |
icon | 图标参数,内部支持html字符串图标,传入组件时需要实现icon插槽 | string |(key?: string)=>string | 其他类型 |
false |
undefined |
disabled | 是否禁用菜单项 | boolean | (key?: string)=>boolean |
false |
undefined |
divided | 是否显示分割线 | boolean | (key?: string)=>boolean |
false |
undefined |
tip | 没项菜单后面的小提示 | string | (key?: string)=>string |
false |
'' |
hidden | 是否隐藏该项 | boolean | (key?: string)=>boolean |
false |
undefined |
children | 子菜单列表信息 | MenusItemOptions[] |
false |
undefined |
enter | 菜单项移入事件,返回null 或false 不展开子菜单 |
Function() |
false |
undefined |
click | 菜单项点击事件,返回null 或false 不关闭菜单 |
Function() |
false |
undefined |
属性 | 描述 | 类型 | 是否必填 | 默认值 |
---|---|---|---|---|
menus | 菜单列表信息 | MenusItemOptions[] |
true |
[] |
menusClass | 菜单外层 div 的 class 名 |
string |
false |
null |
itemClass | 菜单每一项的class 名 |
string |
false |
null |
minWidth | 菜单容器最小宽度 | number | string |
false |
none |
maxWidth | 菜单容器最打宽度 | number | string |
false |
none |
zIndex | 菜单层级 | number | string |
false |
3 |
direction | 菜单打开方向 | left | right |
false |
right |
属性 | 描述 | 类型 | 是否必填 | 默认值 | 插槽传入值 |
---|---|---|---|---|---|
menus | 菜单列表信息 | MenusItemOptions[] |
true |
[] | |
event | 鼠标事件信息(指令使用时不传) | Event |
与position 必填一项 |
{} | |
menusClass | 菜单外层 div 的 class 名 |
string |
false |
null |
|
itemClass | 菜单每一项的class 名 |
string |
false |
null |
|
minWidth | 菜单容器最小宽度 | number | string |
false |
none |
|
maxWidth | 菜单容器最打宽度 | number | string |
false |
none |
|
zIndex | 菜单层级 | number | string |
false |
3 |
|
direction | 菜单打开方向 | left | right |
false |
right |
|
open | 控制菜单组件显示 | boolean |
true |
false |
|
args | 附加参数 | unknown |
false |
undefined |
|
default | 默认插槽 | Slot |
false |
- | activeIndex : 当前选中索引, menu : 当前菜单项 MenusItemOptions , index : 当前菜单索引 |
icon | 图标插槽 | Slot |
false |
- | activeIndex : 当前选中索引, menu : 当前菜单项 MenusItemOptions , index : 当前菜单索引 |
label | 菜单标题插槽 | Slot |
false |
- | activeIndex : 当前选中索引, menu : 当前菜单项 MenusItemOptions , index : 当前菜单索引 |
suffix | 菜单后缀插槽 | Slot |
false |
- | activeIndex : 当前选中索引, menu : 当前菜单项 MenusItemOptions , index : 当前菜单索引 |
配置参数与方法使用相同
指令使用方式 | 描述 | 参数类型 | 参数是否必填 | 默认值 |
---|---|---|---|---|
v-menus | 绑定元素右击打开菜单 | MenuOptions |
true |
- |
v-menus:all | 绑定元素左右击均可打开菜单 | MenuOptions |
true |
- |
v-menus:left | 绑定元素左击打开 | MenuOptions |
true |
- |
v-menus:right | 绑定元素右击打开 | MenuOptions |
true |
- |