可以在uni-app或vue脚手架项目使用
引入组件会接管页面右键事件,所有options为空数组时,在页面右键将没有反应
rightMenu.vue
<template>
<view>
<view v-if="show" class="contextMenu" :style="lay_style" @contextmenu.stop="() => {return false}">
<view class="menu-lay" v-for="(item, index) in options" :key="index">
<view class="menu-solid" v-if="item.type == 'solid'"></view>
<view class="menu-list" v-else @click="onMenu(item, index)">
<image class="menu-icon" :src='item.icon' v-if="item.icon"></image>
<view class="menu-name" :style="{color: item.color || props.color}">{{item.name}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
/**
* rightMenu 右键菜单
* @description 弹出层组件,为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {Object} props 配置对象
* @property {Number} props.width 弹框宽度 单位px(默认160)
* @property {String} props.color 全局菜单字体颜色 (默认#333333)
* @property {Array} options 菜单列表
* @property {String} options.name 菜单名字
* @property {String} options.icon 菜单图标
* @property {String} options.type 菜单或分界线(菜单可不填,分界线:solid)
* @property {String} options.color 菜单文字颜色
* @property {Boolean} options.disabled 是否禁用
* @event {Function} change 点击菜单触发(当前项,索引)
*/
export default {
props: {
options: {
type: Array,
default() {
return []
}
},
props: {
type: Object,
default: () => {
return {
width: 160,
color: '#333333'
}
}
}
},
data() {
return {
show: false,
lay_style: {}
}
},
created() {
document.addEventListener('contextmenu', this.showContextMenu);
},
beforeDestroy() {
document.removeEventListener('contextmenu', this.showContextMenu);
},
methods: {
showContextMenu(event) {
event.preventDefault();
this.show = false
const x = event.pageX;
const y = event.pageY;
const w = this.props.width
/**
// uni-app项目可使用官方api
const systemInfo = uni.getSystemInfoSync();
const width = systemInfo.windowWidth;
const height = systemInfo.windowHeight;
*/
const width = window.innerWidth
const height = window.innerHeight
const obj = {
width: w,
left: x + 'px',
top: y + 'px'
}
if (+w + +x > width) obj.left = +x - +w + 'px'
let dh = this.options.filter(item => !item.type || item.type != 'solid').length * 32 +
this.options.filter(item => item.type == 'solid').length * 7 + 7
if (dh + +y > height) obj.top = +y - +dh + 'px'
this.$set(this, 'lay_style', obj)
this.$nextTick(() => {
this.show = true
})
},
onMenu(item, index) {
if (item.type == 'solid' || item.disabled) return false
this.show = false
this.$emit('change', item, index)
}
}
}
</script>
<style lang='scss' scoped>
view {
box-sizing: border-box;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.contextMenu {
width: 160px;
position: fixed;
background: #FFFFFF;
padding: 3.5px;
border-radius: 11px;
border: 2px solid #F5F5F5;
box-shadow: 0 4px 8px #F5F5F5;
z-index: 998;
animation-name: fadeIn;
animation-duration: .5s;
animation-fill-mode: forwards;
.menu-lay {
width: 100%;
.menu-list {
width: 100%;
height: 32px;
border-radius: 7px;
padding: 0 8px;
display: flex;
align-items: center;
cursor: pointer;
&:hover {
background: #F5F5F5;
}
.menu-icon {
width: 18px;
height: 18px;
margin-right: 7px;
display: block;
}
.menu-name {
font-size: 14px;
color: #333333;
}
}
.menu-solid {
margin: 3.5px;
height: 1px;
background: #F5F5F5;
}
}
}
</style>
示例
<template>
<view>
<rightMenu :options="options" @change="change"></rightMenu>
</view>
</template>
<script>
import rightMenu from '@/components/rightMenu/index.vue'
const icon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAUJJREFUWEftljFywjAURFcFla9AZqBJk0vkJoQULuN/g8ANvildJNyEXIKGJswkV3CVwpnPfDM2YCRZMG6kGVdaaZ/XtrwGAw8zsD8iwE0TIKJnyyPdM/O+qbkJABFNAHwCsAGI9xeAeQ0SDHDBXAy6hoDKtWDmpYjOAIjoxfPLmOmdS7xT21oiqkTDzAfvI4DeyUYJbfuczjuZy6JrAO8SjT6j1otio2HmuU1Tz18DaEXjuqGvLgLEBGICMYGYgFcCRLQC8Aog0SN363j0PqmuBPDBzG+9/gVZlv0YY8aOphdlVVX95nn+0AsgTdNRkiSPIQBlWe6KovhzAfjWLjA97W0hAM212jnE59gfmoWk7gPSBbz6gAdgdyVrdLta5LGvl3QNYNlZShVEIO4x7lPLQ0iDa3mIeasVh27Ud/3gCfwDgzfQIRDvSjkAAAAASUVORK5CYII='
export default {
components: {
rightMenu
},
data() {
return {
options: [{
name: '新建文件夹',
icon: icon
},
{
type: 'solid'
},
{
name: '上传文件',
icon: icon
},
{
name: '上传文件夹',
icon: icon,
color: 'red',
disabled: true
}
]
}
},
methods: {
change(item, index) {
}
}
}
</script>
效果图