08335 / hivui-platform-template
hivui平台项目模板
Newer
Older
hivui-platform-template / project / hivuiMain / components / contextMenu / index.vue
caibinghong on 4 Jun 2021 add
<template>
    <div class="context-menu context-menu-container"
         :class="openPosition"
         v-if="visible"
         :style="contextMenuPosition"
         v-click-outside="close" 
         @click="close"
         @mouseenter="visble=true"
         @mouseleave="visible=false"
         ref="contextMenu"

    >
        <ul>
            <context-menu-item
                    :field="field"
                    v-for="(menuItem, index) in menuItems"
                    :item="menuItem"
                    :key="index">
            </context-menu-item>
        </ul>
    </div>
</template>

<script>
/* eslint-disable prefer-destructuring */

import ContextMenuItem from './ContextMenuItem.vue';

/**
 * A simple context menu component
 *
 * ```html
 * <ContextMenu :menu-items="[....]"/>
 * ```
 */
export default {
  props: {
    menuItems: {
      type: Array,
      required: true,
    },
    field:{
      type:String,
      default:'title'
    }
  },
  provide(){
    let me=this;
    return {
      getActiveKey(){
        return me.activeKey;
      },
      setActiveKey(key){
        me.activeKey = key;
      }
    }
  },
  data() {
    return {
      visible: false,
      activeKey:'',
      contextMenuPosition: {
        top: 0,
        left: 0,
      },
      openPosition: 'context-menu-open-right',
    };
  },

  methods: {
    close() {
      this.visible = false;
    },

    /**
     * Accepts an Object with an `x, y` position or an instance of Event
     */
    open(position) { 
      this.visible = true;
      this.$nextTick(() => { 
        let x = 0;
        let y = 0;
        if (typeof position !== 'undefined' && typeof position === 'object') {
          if (position instanceof Event) {
            const windowWidth = window.innerWidth;
            // const contextMenuWidth = this.$refs.contextMenu.getBoundingClientRect().width;  //ie  getBoundingClientRect   null
            const contextMenuWidth = this.$refs.contextMenu.offsetWidth;

            let pageX = position.pageX;
            let pageY = position.pageY;

            // let elRect = position.currentTarget.getBoundingClientRect(); //ie  getBoundingClientRect   null
            let elRect = (position.currentTarget||position.target).getBoundingClientRect();

            if( position.type != "contextmenu"){
              pageX = elRect.left;
              pageY = elRect.top+elRect.height;
              if(pageX>=(windowWidth - contextMenuWidth*2)){
                this.openPosition = 'context-menu-open-left';
                x = windowWidth<(pageX+contextMenuWidth)?(windowWidth-contextMenuWidth):pageX;                
              }else{
                this.openPosition = 'context-menu-open-right';
                x = pageX;
              }
            }else{
              if (pageX >= (windowWidth - contextMenuWidth)) {
                this.openPosition = 'context-menu-open-left';
                x = windowWidth - contextMenuWidth - 10;
              } else {
                this.openPosition = 'context-menu-open-right';
                x = pageX;
              }
            }
            y = pageY;
          } else {
            x = position.x;
            y = position.y;
          }
        }

        this.contextMenuPosition = {
          left: `${x}px`,
          top: `${y}px`,
        };
      });
    },
  },

  components: {
    'context-menu-item': ContextMenuItem,
  },

  directives: {
    'click-outside': {
      inserted: function (el) {
        document.body.appendChild(el)
      },
      bind(el, binding, vnode) {
        el.clickOutsideEvent = (event) => {
          // here I check that click was outside the el and his childrens
          if (!(el === event.target || el.contains(event.target))) {
            // and if it did, call method provided in attribute value
            vnode.context[binding.expression](event);
          }
        };
        document.body.addEventListener('click', el.clickOutsideEvent);
      },
      unbind(el) {
        document.body.removeEventListener('click', el.clickOutsideEvent);
      },
    }
  },
};
</script>

<style lang="less">
    @context-menu-border-radius: 0px;

    .context-menu-container {
        position: absolute;
        user-select: none;
        z-index: 100;
    }

    .context-menu {
        background: #fff;
        border-radius: @context-menu-border-radius;
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);

        ul {
            margin: 0;
            padding: 0;
            list-style: none;

            :first-child {
                border-top-right-radius: @context-menu-border-radius;
                border-top-left-radius: @context-menu-border-radius;
            }

            :last-child {
                border-bottom-right-radius: @context-menu-border-radius;
                border-bottom-left-radius: @context-menu-border-radius;
            }

            li {
                position: relative;
                padding: 5px;
                display: block;
                line-height: 25px;
                cursor: pointer;

                .label {
                    // display: flex;
                    white-space: nowrap;
                    .iconfont{
                      margin-right: 5px;
                    }
                    .item-label {
                        margin-right: 10px;
                    }
                    .children-indicator{
                      float: right;
                    }
                }

                &.item-disabled {
                    cursor: not-allowed;
                    opacity: 0.3;
                }

                ul {
                    display: none;
                }
                &.item-active{
                  background: #0066cc;
                   >.label{
                      color:#fff;
                    }
                }
                &:hover {
                    background: #0066cc;
                    >.label{
                      color:#fff;
                    }
                    > ul {
                        position: absolute;
                        // left: calc(100% + 2px);
                        left:100%;
                        top: 0;
                        display: inline-block;
                        min-width: 100px; 
                    }
                }
            }
        }

        &.context-menu-open-left {
            ul {
                li {
                    &:hover {
                        > ul {
                            left: auto;
                            // right: calc(100% + 2px);
                            right: 100%;
                        }
                    }
                }
            }
        }
    }
</style>