详解Element 指令clickoutside源码分析

yizhihongxing

详解Element 指令clickoutside源码分析攻略

简介

这篇攻略将详细介绍Element UI库中使用的指令clickoutside的源码实现。常常需要在页面中对元素执行点击外部关闭操作,这种需求就可以通过clickoutside指令来实现。

环境

本篇攻略基于Vue.js和Element UI库实现。

功能

clickoutside指令的主要功能是用于监听元素外面的点击事件,从而可以实现定义点击元素外面的区域时关闭某些DOM节点。

使用方式

clickoutside指令的使用方式为:

<div v-clickoutside="handler"></div>

注意:需要在Vue实例的directives属性中全局注册这个指令。

实现原理

clickoutside指令本质上是一个Vue自定义指令,其主要实现在src/directives/clickoutside.js中。该指令主要实现了下面两个功能:

  1. 监听元素外部的鼠标点击事件
  2. 触发绑定到该指令的方法

监听鼠标点击事件

clickoutside指令的核心功能是监听鼠标点击事件,并决定是否触发相关的事件。监听外部点击事件的原理是通过事件冒泡来实现的,包括以下几个步骤:

  1. 给需要监听的元素添加一个mousedown事件,当这个函数被触发时,会对document添加一个mouseup事件,同时记录鼠标点击时的target。
  2. 当触发mouseup事件时,会先判断点击目标是否是当前元素或其子元素,如果是,则不做任何处理;如果不是,则触发绑定的函数。
  3. 在监听mousemove和mouseup事件期间,需要同时监听document的mouseleave事件,当鼠标移除document时,会触发mouseup事件。

基本代码实现如下:

function bind(el, binding, vnode) {
  const documentHandler = function (e) {
    if (el.contains(e.target)) {
      return false;
    }
    if (binding.expression) {
      binding.value(e);
    }
  };
  el.__vueClickOutside__ = documentHandler;
  document.addEventListener('mousedown', documentHandler);
}

然而,由于鼠标事件的特性,在某些情况下,以上实现会出现一些问题。

  1. mousedown事件会被触发两次
    1. 当外部点击第一个元素时,会触发mousedown事件
    2. 当外部点击第二个元素时,此时外部元素已经被替换了,所以外部元素的mousedown事件会再次触发
  2. 在VPopper组件中,弹出VPopper后,由于弹出框是在外部的,所以会导致VPopper组件的mousedown事件不会被触发,无法正确关闭组件

针对这些问题,clickoutside指令使用了一些技巧来解决。

  1. 在mousedown事件发生时,对于新创建的弹出框元素,需要将其加入到被监听元素列表中,同时将所有监听的元素加入到另一个列表中。并在mouseup时遍历这个列表,判断是否需要触发事件。
  2. 当弹出框出现时,判断鼠标点击的目标是否在被监听元素列表中,如果是,则直接终止后续触发操作。

修正后的代码如下:

function bind(el, binding, vnode) {
  const documentHandler = function (e) {
    if (vnode.context && !vnode.context.popperElm.contains(e.target) && el !== e.target && !el.contains(e.target)) {
      vnode.context[el.__vueClickOutside__].call(null, e);
    }
  };
  el.__vueClickOutside__ = documentHandler;
  binding.def.addEvent(document.documentElement, 'mousedown', documentHandler);
}

const addEvent = function (el, event, handler) {
  if (el.addEventListener) {
    return el.addEventListener(event, handler, false);
  }
  if (el.attachEvent) {
    return el.attachEvent('on' + event, handler);
  }
  el['on' + event] = handler;
};

示例

示例1:使用clickoutside关闭菜单

在菜单弹出框外部时,点击后应该关闭弹出框。

<template>
  <div>
    <el-button type="primary" @click="showMenu = !showMenu">点击弹出菜单</el-button>
    <el-dropdown :show-menu.sync="showMenu" v-clickoutside="handleClose">
      <el-dropdown-menu slot="dropdown">
        <el-dropdown-item v-for="item in list" :key="item">{{ item }}</el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        showMenu: false,
        list: ['选项一', '选项二', '选项三']
      };
    },
    methods: {
      handleClose() {
        this.showMenu = false;
      }
    }
  };
</script>

示例2:在VPopper组件中使用clickoutside

在VPopper弹框外部时,点击后应该关闭弹框。

<template>
  <div>
    <el-button ref="trigger" type="primary" @click="visible = !visible">点击弹出弹框</el-button>
    <el-popover ref="popover" v-model="visible" v-clickoutside="handleClose">
      <p>这里是弹框的内容</p>
      <p>这里是弹框的内容</p>
      <p>这里是弹框的内容</p>
      <p>这里是弹框的内容</p>
      <p>这里是弹框的内容</p>
    </el-popover>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        visible: false
      };
    },
    methods: {
      handleClose() {
        this.visible = false;
      }
    },
    mounted() {
      //调用VPopper的方法,将弹框内容插入到body元素中,弹框外的元素由于组件弹框的位置而被替换
      this.$refs.popover.doDestroy = function () {
        this.$el.parentNode.removeChild(this.$el);
        this.$destroy();
      };
      this.$refs.popover.popperElm = this.$refs.popover.$el;
      document.body.appendChild(this.$refs.popover.$el);
    }
  };
</script>

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Element 指令clickoutside源码分析 - Python技术站

(0)
上一篇 2023年6月10日
下一篇 2023年6月10日

相关文章

  • JS数据类型判断的几种常用方法

    一、题目背景在JavaScript编程中,我们经常需要对数据的类型进行判断,以便进行不同的操作。本文详细讲解了JS数据类型判断的几种常用方法。 二、常用方法1. typeof 运算符这是最常用的判断数据类型的方式。它可以返回一个字符串,表示操作数的类型。它可以判断基本数据类型、“function”和“undefined”类型,但不能判断具体的引用类型。使用方…

    JavaScript 2023年5月27日
    00
  • JS定时器不可靠的原因及解决方案

    JS定时器不可靠的原因及解决方案 什么是JS定时器? JS中有两种类型的定时器: setTimeout setInterval 这两个函数都是用来定时执行某些代码的。setTimeout函数会在指定的时间后执行一次性的操作,而setInterval会每隔指定时间执行一次操作。 JS定时器的不可靠性 JS定时器不可靠的原因是因为定时器的执行是基于事件循环机制的…

    JavaScript 2023年5月28日
    00
  • JavaScript中Promise的使用方法实例

    下面就是关于“JavaScript中Promise的使用方法实例”的完整攻略。 什么是Promise? Promise 是一种异步编程的解决方案,它解决了回调函数嵌套引起的代码可读性差、容易出错和难以维护的问题。通过 Promise,可以更加优雅、可读、容错的编写异步代码。 Promise 的基本语法结构如下: new Promise(function(re…

    JavaScript 2023年5月27日
    00
  • 如何通过Vue自定义指令实现前端埋点详析

    下面将详细讲解如何通过Vue自定义指令实现前端埋点。 什么是前端埋点? 前端埋点是指在页面中插入一些代码,以便跟踪用户在页面中的行为和交互。常见的前端埋点方式包括:统计页面中某个元素的点击次数、记录用户填写表单的时间等等。 Vue自定义指令 Vue自定义指令可以将一些常见的DOM操作封装起来,使得在Vue组件中使用更加方便。 创建自定义指令 在Vue中创建自…

    JavaScript 2023年6月11日
    00
  • javascript中创建对象的几种方法总结

    JavaScript中创建对象的几种方法总结 JavaScript中创建对象的方式有多种,下面将详细介绍Javascript中创建对象的几种方法,以及它们的使用场景。 1. 使用对象字面量 使用对象字面量方式可以创建一个新的对象,这是一种最简单和常用的方式。对象字面量是由一对花括号({})包含着一个无序的键值对(key:value)列表,其中键名是字符串,值…

    JavaScript 2023年5月27日
    00
  • JS代码判断集锦大全第3/5页

    这篇“JS代码判断集锦大全第3/5页”的攻略是一篇非常详细的教程,下面我将逐步地为您介绍它的主要内容。 攻略概述 这篇攻略主要是针对“JS代码判断集锦大全第3/5页”这一题目,介绍其中一些常见的判断语句和用法。在学习本文之前,您需要具备一定的JavaScript编程基础。 判断语句 判断语句是JavaScript程序中非常重要的部分之一。您可以利用判断语句来…

    JavaScript 2023年5月27日
    00
  • js模拟点击以提交表单为例兼容主流浏览器

    以下是详细讲解“js模拟点击以提交表单为例兼容主流浏览器”的完整攻略。 什么是js模拟点击以提交表单 js模拟点击以提交表单是指在前端页面上通过JavaScript代码模拟用户点击提交按钮并提交表单数据。通常用于从前端页面向后台服务器提交数据并触发后台相关操作。 兼容主流浏览器的攻略 由于不同浏览器的JS引擎有差异,因此需要针对不同的浏览器进行兼容。 下面是…

    JavaScript 2023年5月27日
    00
  • 通过fastclick源码分析彻底解决tap“点透”

    通过fastclick源码分析彻底解决tap“点透” 背景 在移动端开发过程中,常常会遇到“点透”的问题。例如,当一个元素的click事件和另一个元素的touchend事件同时被触发时,就会发生“点透”,相当于用户点了下下一层的元素。为了避免这种问题的出现,我们可以使用第三方库 fastclick 来解决这一问题,此处将通过 fastclick 的源码分析来…

    JavaScript 2023年6月11日
    00
合作推广
合作推广
分享本页
返回顶部