Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
vue3-menus
Advanced tools
Vue3.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 v-model:open="isOpen" :event="eventVal" :menus="menus.menus" hasIcon>
<template #icon="{item: {activeIndex}}">{{activeIndex}}</template>
<template #label="{ item: { item } }">插槽:{{ item.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',
icon: {
node: SyncOutlined,
option: {
spin: true
}
},
click: () => location.reload(),
divided: true
},
{
label: "另存为(A)...",
tip: 'Ctrl+S'
},
{
label: "打印(P)...",
tip: 'Ctrl+P',
icon: {
node: Printer,
option: {
color: 'red'
}
},
click: () => window.print(),
},
{
label: "投射(C)...",
divided: true
},
{
label: '发送到你的设备',
icon: WindowsOutlined,
children: [
{
label: 'iPhone',
},
{
label: 'iPad'
},
{
label: 'Windows 11'
}
]
},
{
label: "为此页面创建二维码",
divided: true,
icon: {
node: QrcodeOutlined,
option: {
style: {
color: 'aqua'
}
}
}
},
{
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="{item: {activeIndex}}">{{activeIndex}}</template>
<template #label="{ item: { item } }">插槽:{{ item.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>
MenusItemOptions
属性 | 描述 | 类型 | 是否必填 | 默认值 |
---|---|---|---|---|
label | 菜单项名称 | string | true | — |
style | 每一项菜单的自定义样式 | object | false | {} |
icon | string : 传入图标html代码、object : 传入组件或者{node: 组件, option: 组件配置参数} | string | object | false | undefined |
disabled | 是否禁用菜单项 | boolean | false | undefined |
divided | 是否显示分割线 | boolean | false | undefined |
tip | 没项菜单后面的小提示 | string | false | '' |
click | 菜单项点击事件,返回null 或false 不关闭菜单 | Function() | false | undefined |
children | 子菜单列表信息 | MenusItemOptions[] | false | undefined |
MenuOptions
属性 | 描述 | 类型 | 是否必填 | 默认值 |
---|---|---|---|---|
menus | 菜单列表信息 | MenusItemOptions[] | true | [] |
menusStyle | 菜单容器的样式 | object | false | {} |
menusItemClass | 菜单每一项的class 名 | string | false | null |
event | 鼠标事件信息(指令使用时可以不传) | Event | 与position 必填一项 | {} |
position | 手动传入菜单显示位置(指令使用时可以不传) | {x: number, y: number} | 与event 必填一项 | {} |
minWidth | 菜单容器最小宽度 | number | string | false | none |
maxWidth | 菜单容器最打宽度 | number | string | false | none |
zIndex | 菜单层级 | number | string | false | 3 |
Vue3Menus
参数属性 | 描述 | 类型 | 是否必填 | 默认值 | 插槽传入值 |
---|---|---|---|---|---|
open | 控制菜单组件显示 | boolean | true | false | false |
default | 默认插槽 | Slot | false | - | activeIndex : 当前选中项, item : 当前菜单属性值 |
icon | 图标插槽 | Slot | false | - | activeIndex : 当前选中项, item : 当前菜单属性值 |
label | 菜单标题插槽 | Slot | false | - | activeIndex : 当前选中项, item : 当前菜单属性值 |
suffix | 菜单后缀插槽 | Slot | false | - | activeIndex : 当前选中项, item : 当前菜单属性值 |
指令使用方式 | 描述 | 参数类型 | 参数是否必填 | 默认值 |
---|---|---|---|---|
v-menus | 绑定元素右击打开菜单 | MenuOptions | true | - |
v-menus:all | 绑定元素左右击均可打开菜单 | MenuOptions | true | - |
v-menus:left | 绑定元素左击打开 | MenuOptions | true | - |
v-menus:right | 绑定元素右击打开 | MenuOptions | true | - |
FAQs
Vue3.0 左右键菜单
The npm package vue3-menus receives a total of 82 weekly downloads. As such, vue3-menus popularity was classified as not popular.
We found that vue3-menus demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.