Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/xfy520/vue3-menus

Vue3.0 自定义右键菜单
https://github.com/xfy520/vue3-menus

menus vue3 vue3-menus

Last synced: about 2 months ago
JSON representation

Vue3.0 自定义右键菜单

Awesome Lists containing this project

README

        

# vue3-menus

Vue3.0 自定义右键菜单,支持 Vite2.0,[官网](https://doc.wssio.com/opensource/vue3-menus/)

Vue3.0 原生实现完全自定义右键菜单组件, 零依赖,可根据可视区域自动调节显示位置,可支持插槽完全重写每一项菜单

![演示](./example/vue3-menus.png)

## 在线演示

- [完整菜单功能演示](https://codepen.io/xfy520/pen/yLXNqzy)
- [复制粘贴演示](https://codepen.io/xfy520/pen/xxrGJdg)

## 快速安装

### npm 安装

```shell
npm install vue3-menus
```

```shell
yarn add vue3-menus
```

### CDN

```html

```

## 使用(Vite 情况下同样使用)

CDN引入则不需要 `app.use(Vue3Menus)`
> 样例中使用的是`@ant-design/icons-vue`图标与`@element-plus/icons`图标、图标可以使用`html`代码传入、也可以通过插槽`自定义图标`、也可以`完全重写每一项菜单`

```js
// 全局注册组件、指令、方法
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');
```

```html
<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 }
},
});

```

```css
.div {
display: inline-block;
background-color: aqua;
margin: 0 20px;
line-height: 200px;
padding: 0 20px;
height: 200px;
}
```

### 指令方式使用

```html

指令方式打开菜单

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 }
},
});

```

### 方法方式使用

```html

事件方式打开菜单

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 }
},
});

```

### 组件方式使用

```html

组件方式打开菜单


{{activeIndex}}
插槽:{{ menu.label }}

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 }
},
});

```

## 参数说明

### 单个菜单项参数`MenusItemOptions`

| 属性 | 描述 | 类型 | 是否必填 | 默认值 |
| :------: | :----------------------------------------------------------: | :--------------------: | :------: | :---------: |
| 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` | - |