关于困扰我一下午的vue指令 clickoutside.js;以及我对指令的测试结果

https://github.com/ElemeFE/element/blob/d419e260d0fc1463ccbc4f5e45e129ec0e972255/src/utils/clickoutside.js

下面的代码是element ui中的clickoutside.js

const on = (function() {
  if (!Vue.prototype.$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);
      }
    };
  }
})();


import Vue from '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 = {}) {
    console.log(vnode.context.popperElm)
    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;
      }
       
    console.log(binding.expression);
    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">
 * ```
 */
export default {
  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];
  }
};

这个是我写的alert.vue

<template>
    <div class='dialog-alert' v-show="alert">
        <div class='dialog-content'v-clickoutside="hideAlert">
            <div class="dialog-body">{{message}}</div>
            <a href="javascript:;" class="dialog-button" @click="hideAlert">确定</a>
        </div>
        <div class="dialog-mask"></div>
    </div>
</template>
<script>
import clickoutside from'./../directives/vue-directive-clickout.js'
 export default{
     props:{
         alert:{
             type:Boolean,
             required: true
         },
         message:{
             type:String,
             required: true
         }
     },
     methods:{
        hideAlert() {
            this.$emit('hideAlert');
        }
     },
    directives: {
        clickoutside
    },

 }

</script>
<style lang="scss" rel="stylesheet/scss" scoped>
   .dialog-alert {
        z-index: 21px;
        .dialog-content {
            position: absolute;
            left: 50%;
            top: 50%;
            margin-left: -4.6875rem;
            margin-top: -1.734375rem;
            z-index: 21;
            border-radius: .3125rem;
            background-color: #fff;
        }
        .dialog-body,
        .dialog-button {
             9.375rem;
            height: 1.734375rem;
            margin: 0 auto;
            line-height: 1.734375rem;
        }
        .dialog-body {
            border-bottom: 1px solid #999;
            color: #6c6c6c
        }
        .dialog-button {
            color: #ff5000
        }
    }
    .dialog-mask {
        position: absolute;
         100%;
        height: 100%;
        top: 0;
        left: 0;
        bottom: 0;
        z-index: 20;
        background: rgba(0, 0, 0, .6)
    }
</style>

还有我在login.vue中写的触发条件;loginIn函数是将alert的值改为true,hideAlert是将alert的值设置为false

    <button class="btn-login" type="button" @click="loginIn">登录</button>
        
    <alert :alert="alert" message="wowoowow" @hideAlert='hideAlert'></alert>

这里的我的问题就是为什么点击登录的时候,弹窗还出的来;点击的时候hideAlert被执行了 所以应该是false;所以呢我就就行了各种的测试,始终找不到答案。

最后呢?我在走路回家的路上想通了这个问题,因为mouseup、mousedown先执行的,click时间后执行的。有点小难受。

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<div id="bbb">点击</div>
<script>
     document.getElementById('bbb').addEventListener('click', function(){
         console.log('click')
     }, false);
     document.addEventListener('mouseup', function(){
         console.log('mouseup')
     }, false);
     document.addEventListener('mousedown', function(){
         console.log('mousedown')
     }, false);
</script>
</body>
</html>

结果:

测试的结果就是:  clickoutside.js

1、当一个指令在同一页面上有多个时;绑定的是document事件;document的时间被重复触发;

原文地址:https://www.cnblogs.com/heyinwangchuan/p/8124438.html