VUE_网页自定义右键菜单组件

106 篇文章 7 订阅

在这里插入图片描述

可以在uni-appvue脚手架项目使用

引入组件会接管页面右键事件,所有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>				

效果图
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值