VUE 鼠标右键菜单组件

1.组件,分为Index.Vue,和Item.vue

//效果

 

1.此文件为index.Vue
<template> <transition name="fade"> <div class="elx-context-menu" v-show="visible" :style="{width: width+'px', top: currentY+'px', left: currentX+'px'}"> <ul> <context-menu-item v-for="item in data" :key="item.label" :data="item" :tip-show="tipShow" @action="action"> </context-menu-item> </ul> </div> </transition> </template> <script> import ContextMenuItem from './item'; export default { name: 'ContextMenu', componentName: 'ContextMenu', components: { ContextMenuItem }, props: { width: {// type: Number, default: 80 }, x: {// X坐标 type: Number, default: 0 }, y: {// Y坐标 type: Number, default: 0 }, data: {// 显示右键菜单的数据 type: Array, default: function() { return []; } }, visible: {// 是否显示右键菜单 type: Boolean, default: false }, tipShow: {// 是否显示提示 type: Boolean, default: true } }, data() { return { currentX: 0, currentY: 0 }; }, methods: { action(data) { if (!data.disabled) { this.$emit('action', data); } }, changePos() { const gap = 5; const bodyClientHeight = document.body.clientHeight; const bodyClientTop = document.body.clientTop; const height = this.$el.clientHeight; const elBottom = height + this.currentY; const viewHeight = bodyClientHeight + bodyClientTop; if (viewHeight < elBottom) { this.currentY = viewHeight - height - gap; } }, handleDisplay() { this.contentMenuShow = false; } }, watch: { visible(val) { if (val) { const self = this; self.$nextTick(() => { self.changePos(); }); } }, x(val) { this.currentX = val; }, y(val) { this.currentY = val; this.changePos(); } }, created() { this.currentX = this.x; this.currentY = this.y; }, mounted() { this.changePos(); window.addEventListener('resize', this.handleDisplay); }, beforeDestroy() { window.removeEventListener('resize', this.handleDisplay); } }; </script>

2.item.vue


此文件为item.Vue
<template>

  <li
    :class="data.disabled?'disabled':''"
    @click.stop.prevent="exec"
    @mouseenter.stop.prevent="showChild"
    @mouseleave.stop.prevent="hideChild">
    <el-tooltip :content="data.label" placement="left" :hide-after="500" v-if="tipShow">
      <div class="elx-context-menu-title">
        <span :class="data.class">
          <span v-if="data.icon" :class="data.icon"></span>
          <span v-if="data.label" v-text="data.label"></span>
          <!-- <node-content :node="data"></node-content> -->
        </span>
        <template v-if="'children' in data">
          <span v-if="data.children.length>0" class="uex-icon-caret-right"></span>
        </template>
      </div>
    </el-tooltip>
    <div class="elx-context-menu-title" v-if="!tipShow" :title="data.label">
      <span :class="data.class">
        <span v-if="data.icon" :class="data.icon"></span>
         <span v-if="data.label" v-text="data.label"></span>
        <!-- <node-content :node="data"></node-content> -->
      </span>
      <template v-if="'children' in data">
        <span v-if="data.children.length>0" class="uex-icon-caret-right"></span>
      </template>
    </div>
    <ul
      v-if="'children' in data"
      v-show="visible"
      :style="{top: pos.top, bottom: pos.bottom}">
      <context-menu-item
        v-for="(item,index) in data.children"
        :key="index"
        :data="item"
        @action="action">
      </context-menu-item>
    </ul>
  </li>
</template>
<script>
export default {
    name: 'ContextMenuItems',

    componentName: 'ContextMenuItems',

    props: {
        data: {
            type: Object,
            default() {
                return {};
            }
        },
        tipShow: {
            type: Boolean,
            default: false
        }
    },

    components: {},

    data() {
        return {
            pos: {
                top: '0px',
                bottom: 'auto'
            },
            visible: false
        };
    },
    methods: {
        getElementPosition(el) {
            let x = 0;
            let y = 0;
            while (el != null) {
                x += el.offsetLeft;
                y += el.offsetTop;
                // eslint-disable-next-line no-param-reassign
                el = el.offsetParent;
            }
            return { x, y };
        },
        exec() {
            if (!this.data.disabled) {
                this.$emit('action', this.data);
            }
        },
        action(data) {
            if (!data.disabled) {
                this.$emit('action', data);
            }
        },
        changeStyle() {
            const self = this;
            if (self.$el.childNodes[1]) {
                if (typeof self.$el.childNodes[1].tagName === 'string') {
                    if (self.$el.childNodes[1].tagName.toLowerCase() === 'ul') {
                        const bodyClientHeight = document.body.clientHeight;
                        const bodyClientTop = document.body.clientTop;
                        const viewHeight = bodyClientHeight + bodyClientTop;
                        const clientTop = this.getElementPosition(self.$el.childNodes[1]).y;
                        const height = self.$el.childNodes[1].clientHeight;
                        const elBottom = height + clientTop;
                        if (viewHeight < elBottom) {
                            this.pos.top = 'auto';
                            this.pos.bottom = '0px';
                        } else {
                            this.pos.top = '0px';
                            this.pos.bottom = 'auto';
                        }
                    }
                }
            }
        },
        showChild() {
            this.visible = true;
        },
        hideChild() {
            this.visible = false;
            this.pos.top = '0px';
            this.pos.bottom = 'auto';
        }
    },
    watch: {
        visible(val) {
            if (val) {
                const self = this;
                this.$nextTick(() => {
                    self.changeStyle();
                });
            }
        }
    },
    created() {
    },
    mounted() {
        this.changeStyle();
    }
};
</script>

 

3.调用组件:

 

import ContextMenu from './content-menu/index';

// 我这里是表格调用
  @row-contextmenu="rowContextmenu1",在表格中放入改事件,放在el-table上,下面是直接使用方法,及指令
<el-table :data="tableData" border style="width: 100%" @contextmenu.native="handleContextMenu" @row-contextmenu="rowContextmenu2" v-contextmenu="buttonActionData2" @contextmenu-action="buttonAction" > <el-table-column prop="stepInst" label="指令" show-overflow-tooltip></el-table-column> <el-table-column prop="stepType" label="所属区域" show-overflow-tooltip></el-table-column> </el-table>
//js
methods: { buttonAction: function(data) { console.log(data.action); }, rowContextmenu2: function(row, event) { this.rowContextmenu = true; this.activeRow = row; }, handleContextMenu: function() { if (this.rowContextmenu) { this.buttonActionData2 = this.activeRow.actions; } else { this.buttonActionData2 = []; } this.rowContextmenu = false } },
//data
tableData: [ { 'stepInst': 'authVerify', 'stepType': '输入区', 'actions': [ {'icon': 'uex-icon-edit', 'label': 'test1test1test1', 'action': 'aaaa'}, {'label': 'test2', 'action': 'bbbb'} ] }, { 'stepInst': 'authVerify', 'stepType': '输入区', 'actions': [ {'label': 'test1test1test1', 'action': 'aaaa'}, {'label': 'test2', 'action': 'bbbb'} ] }, { 'stepInst': 'paramCheck', 'stepType': '输入区', 'actions': [ {'label': 'test3', 'action': 'aaaa1'}, {'label': 'test4', 'action': 'bbbb1'} ] }, { 'stepInst': 'paramsConvert', 'stepType': '输入区', 'actions': [ { 'label': 'test1test1test1test1', 'action': 'action1' }, { 'label': 'test2test2test2', 'action': 'action2', 'children': [ { 'label': 'test21est21est21', 'action': 'action21', 'children': [ { 'label': 'test211test211test211', 'action': 'action211' }, { 'label': 'test212test212test212', 'action': 'action212' } ] }, { 'label': 'test22test22test22', 'action': 'action22' }, ] } ] } ], buttonActionData2: [], rowContextmenu: false
//上面是在table中添加组件来使用
//通过右键配置使用
<el-table :data="tableData" border style="width: 100%" @row-contextmenu="rowContextmenu1"> <el-table-column prop="stepInst" label="指令" show-overflow-tooltip></el-table-column> <el-table-column prop="stepType" label="所属区域" show-overflow-tooltip></el-table-column> </el-table>
<
ContextMenu @action="action" :tip-show="false" :data="actionData" :width="90" :visible="contentMenuShow" :x="pos.x" :y="pos.y"> </ContextMenu>
//data
tableData: [ { 'stepInst': 'authVerify', 'stepType': '输入区', 'actions': [ {'icon': 'uex-icon-edit', 'label': 'test1test1test1', 'action': 'aaaa'}, {'label': 'test2', 'action': 'bbbb'} ] }, { 'stepInst': 'authVerify', 'stepType': '输入区', 'actions': [ {'label': 'test1test1test1', 'action': 'aaaa'}, {'label': 'test2', 'action': 'bbbb'} ] }, { 'stepInst': 'paramCheck', 'stepType': '输入区', 'actions': [ {'label': 'test3', 'action': 'aaaa1'}, {'label': 'test4', 'action': 'bbbb1'} ] }, { 'stepInst': 'paramsConvert', 'stepType': '输入区', 'actions': [ { 'label': 'test1test1test1test1', 'action': 'action1' }, { 'label': 'test2test2test2', 'action': 'action2', 'children': [ { 'label': 'test21est21est21', 'action': 'action21', 'children': [ { 'label': 'test211test211test211', 'action': 'action211' }, { 'label': 'test212test212test212', 'action': 'action212' } ] }, { 'label': 'test22test22test22', 'action': 'action22' }, ] } ] } ], pos: { x: 0, y: 0 }, actionData: [{'label': 'test2', 'action': 'bbbb'}], contentMenuShow: false, buttonActionData1: [ { 'label': 'test1test1test1test1', 'action': 'action1' }, { 'label': 'test2test2test2', 'action': 'action2', 'children': [ { 'label': 'test21est21est21', 'action': 'action21', 'children': [ { 'label': 'test211test211test211', 'action': 'action211' }, { 'label': 'test212test212test212', 'action': 'action212' } ] }, { 'label': 'test22test22test22', 'action': 'action22' }, ] } ], buttonActionData2: [], buttonShow: true, rowContextmenu: false
//js
methods: { getEventPos: function(e) { var x = e.clientX; var y = e.clientY; return { 'x': x, 'y': y }; }, rowContextmenu1: function(row, event) { var e = event || window.event; var pos = this.getEventPos(e); if (e.which === 3) { this.contentMenuShow = false; this.pos.x = pos.x; this.pos.y = pos.y; this.actionData = row.actions; console.log(this.actionData); this.contentMenuShow = true; } this.preventDefault(e); e.returnValue = false; return false; }, preventDefault: function(e) { e = e || window.event; if (e.preventDefault) { e.preventDefault(); } else { e.returnvalue = false; } }, action: function(data) { alert(data.action); this.contentMenuShow = false; } }, created: function() { }, mounted: function() { var _self = this; this.$nextTick(function() { var el = document.body; var handleDisplay = function() { _self.contentMenuShow = false; } if (el.addEventListener) { el.addEventListener('click', handleDisplay); } else if (el.attachEvent) { el.attachEvent('onclick', handleDisplay); } });
//
组件--下面是直接使用方法,及指令 //data数据 contextmenuData: [ { label: '新增', action: 'add', icon: 'ri-add-line' }, { label: '编辑', action: 'edit', icon: 'ri-edit-box-line', disabled: true }, { label: '删除', action: 'delete', icon: 'ri-delete-bin-7-line' } ], pos: { x: 0, y: 0 }, rowContextmenu: false, //html <ContextMenu @action="action" :tip-show="false" :data="contextmenuData" :width="120" :visible="rowContextmenu" :x="pos.x" :y="pos.y"> </ContextMenu> //js事件 getEventPos(e) { const x = e.clientX; const y = e.clientY; return { x, y }; }, rowContextmenu1(row) { console.log('row', row); const contextmenuData = [ { label: '新增', action: 'add', icon: 'ri-add-line' }, { label: '编辑', action: 'edit', icon: 'ri-edit-box-line', disabled: true }, { label: '删除', action: 'delete', icon: 'ri-delete-bin-7-line' } ]; const e = window.event; const pos = this.getEventPos(e); if (e.which === 3) { this.rowContextmenu = false; this.pos.x = pos.x; this.pos.y = pos.y; this.contextmenuData = contextmenuData; this.rowContextmenu = true; } this.preventDefault(e); e.returnValue = false; return false; }, preventDefault(el) { const e = el || window.event; if (e.preventDefault) { e.preventDefault(); } else { e.returnvalue = false; } return e; }, action(data) { console.log('data.action', data.action); this.rowContextmenu = false; },

这只是我项目中一个简单的demo,有问题,私信我

posted @ 2020-06-29 17:05  Empress&  阅读(4276)  评论(3编辑  收藏  举报