vue自定义组件-select组件

原创
2018/01/19 13:22
阅读数 1.5W

基于vue自定义select组件

index.html——调用页面

<yun-select v-model="select">
    <yun-option label="菜单1" value="1"></yun-option>
    <yun-option label="菜单2" value="2"></yun-option>
    <yun-option label="菜单3" value="3"></yun-option>
</yun-select>

select.js——select组件

Vue.component('yun-select', {
    name: 'ElSelect',
    componentName: 'ElSelect',
    template: '<div class="el-select" v-clickoutside="handleClose">'+
        '<div class="el-input el-input--suffix" @click.stop="toggleMenu" >'+
            '<input class="el-input__inner" type="text" disabled="disabled" v-model="currentValue" />'+
        '</div>'+
        '<div>'+
            '<ul class="el-select-dropdown el-popper" v-show="visbale">'+
                '<slot></slot>'+
            '</ul>'+
        '</div>'+
    '</div>',
    data: function () {
        return {
            currentValue: '',
            visbale:false,
            cachedOptions:[],
        }
    },
    props: {
        value: { // 必须要使用value
     default: '',
    },
    },
    provide() {
        return {
            'select': this
        };
    },
    created(){
        this.$on('handleOptionClick', this.handleOptionSelect);
    },
    mounted(){
        this.setOptionLabel();
    },
    wathch:{
       
    },
    directives: { Clickoutside },
    methods: {
        toggleMenu(){
            this.visbale = !this.visbale;
        },
        handleClose(){
            this.visbale = false;
        },
        setOptionLabel(){
            var flag = false;
            for(var i =0,j=this.cachedOptions.length;i<j;i++){
                if(this.cachedOptions[i].value == this.value){
                    flag = true;
                    this.currentValue = this.cachedOptions[i].label;
                    break;
                }
            }
            if(!flag){
                this.currentValue = this.value;
            }
        },
        handleOptionSelect(option) {
            this.currentValue = option.label;
            this.visbale = false;
            this.$emit('change', option.value);
            this.$emit('input', option.value);
        }
    }
})

option.js——option组件(select子菜单)

Vue.component('yun-option', {
    mixins: [Emitter],
    name: 'ElOption',
    componentName: 'ElOption',
    inject: ['select'],
    template: '<li class="el-select-dropdown__item" @click.stop="selectOptionClick">'+
        '<slot>'+
            '<span>{{ currentLabel }}</span>'+
        '</slot>'+
    '</li>',
    data: function () {
        return {
           
        }
    },
    props: {
        value: {
            type: Number,
            required: true,
        },
        visbale:{
            type: Boolean,
            default:true
        },
        label: [String, Number],
    },  
    created() {
        this.select.cachedOptions.push(this);
    },
    computed: {
        currentLabel() {
            return this.label || (this.isObject ? '' : this.value);
        },
        currentValue() {
            return this.value;
        },
    },
    methods: {
        selectOptionClick(){
            if (this.disabled !== true && this.groupDisabled !== true) {
                this.dispatch('ElSelect', 'handleOptionClick', this);
            }
        },
    }
})

emitter.js——vue订阅与发布

function broadcast(componentName, eventName, params) {
    this.$children.forEach(child => {
      var name = child.$options.componentName;
        
      if (name === componentName) {
        child.$emit.apply(child, [eventName].concat(params));
      } else {
        broadcast.apply(child, [componentName, eventName].concat([params]));
      }
    });
  }
var Emitter = {
    methods: {
      dispatch(componentName, eventName, params) {
        var parent = this.$parent || this.$root;
        var name = parent.$options.componentName;
  
        while (parent && (!name || name !== componentName)) {
          parent = parent.$parent;
  
          if (parent) {
            name = parent.$options.componentName;
          }
        }
        if (parent) {
          parent.$emit.apply(parent, [eventName].concat(params));
        }
      },
      broadcast(componentName, eventName, params) {
        broadcast.call(this, componentName, eventName, params);
      }
    }
  };

clickoutside.js——vue自定义指令事件

const nodeList = [];
const ctx = '@@clickoutsideContext';

let startClick;
let seed = 0;

!Vue.prototype.$isServer && on(document, 'mousedown', e => (startClick = e));

!Vue.prototype.$isServer && on(document, 'mouseup', e => {
  nodeList.forEach(node => node[ctx].documentHandler(e, startClick));
});

function createDocumentHandler(el, binding, vnode) {
  return function(mouseup = {}, mousedown = {}) {
    if (!vnode ||
      !vnode.context ||
      !mouseup.target ||
      !mousedown.target ||
      el.contains(mouseup.target) ||
      el.contains(mousedown.target) ||
      el === mouseup.target ||
      (vnode.context.popperElm &&
      (vnode.context.popperElm.contains(mouseup.target) ||
      vnode.context.popperElm.contains(mousedown.target)))) return;

    if (binding.expression &&
      el[ctx].methodName &&
      vnode.context[el[ctx].methodName]) {
      vnode.context[el[ctx].methodName]();
    } else {
      el[ctx].bindingFn && el[ctx].bindingFn();
    }
  };
}

/**
 * v-clickoutside
 * @desc 点击元素外面才会触发的事件
 * @example
 * ```vue
 * <div v-element-clickoutside="handleClose">
 * ```
 */
var Clickoutside  = {
  bind(el, binding, vnode) {
    nodeList.push(el);
    const id = seed++;
    el[ctx] = {
      id,
      documentHandler: createDocumentHandler(el, binding, vnode),
      methodName: binding.expression,
      bindingFn: binding.value
    };
  },

  update(el, binding, vnode) {
    el[ctx].documentHandler = createDocumentHandler(el, binding, vnode);
    el[ctx].methodName = binding.expression;
    el[ctx].bindingFn = binding.value;
  },

  unbind(el) {
    let len = nodeList.length;

    for (let i = 0; i < len; i++) {
      if (nodeList[i][ctx].id === el[ctx].id) {
        nodeList.splice(i, 1);
        break;
      }
    }
    delete el[ctx];
  }
};

dom.js——dom事件绑定

const isServer = Vue.prototype.$isServer;
/* istanbul ignore next */
 var  on  = (function() {
  if (!isServer && document.addEventListener) {
    return function(element, event, handler) {
      if (element && event && handler) {
        element.addEventListener(event, handler, false);
      }
    };
  } else {
    return function(element, event, handler) {
      if (element && event && handler) {
        element.attachEvent('on' + event, handler);
      }
    };
  }
})();

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部