zoukankan      html  css  js  c++  java
  • VUE 鼠标右键菜单组件

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

    1.此文件为index.Vue
    <template> <transition name="fade"> <div class="elx-context-menu" v-show="visible" :style="{ 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: { {// 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上,
    // 组件
    //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,有问题,私信我

  • 相关阅读:
    SpringBoot整合Swagger2
    AuthenticationToken的元素不满足实际情况,登录的时候需要有学校id或者其他参数
    nginx导入学成静态网页
    springboot使用枚举类型
    springboot配置多个yml文件
    尝试使用freemarker模板引擎生成打印文件
    多版本并发控制 MVCC 实现可重复读
    多版本并发控制 MVCC简介
    模拟3级分类信息查询
    IDEA去掉屏幕中间的白色竖线
  • 原文地址:https://www.cnblogs.com/wangliko/p/13208922.html
Copyright © 2011-2022 走看看