一个因@click.stop引发的bug的解决


Posted in Javascript onJanuary 08, 2019

问题

在项目页面中使用 element popover,设置trigger='click'时点击外部不会触发自动隐藏,但在 element 官网中是可以正常触发的(官方示例),项目中的菜单是自定义写的,所以怀疑是有黑魔法。

查找原因

  1. 将 popover 写在app.vue根组件内,发现可以正常触发自动隐藏。
  2. 在app.vue的 mounted 钩子中加入window.addEventListener('click', () => console.log('window click===>>>>')),发现只有菜单栏外层能够触发。
  3. 检查菜单栏组件,发现代码中<div class="main" @click.stop="isShowWhole = false">,这里的 click 事件使用了 stop 修饰符(阻止冒泡),可能阻止了 popover 外部点击的事件判断,尝试将 stop 修饰符去掉,发现外部点击事件正常触发。

确认代码修改没有副作用

在修复 bug 时,需要注意不会产生额外的 bug,那就需要了解修改的这段代码的含义

@click.stop="isShowWhole = false"

从代码上看,点击 class 为 main 的 div 将会触发左边侧边栏缩略显示,加上 stop 修饰符是为了防止事件冒泡,所以能否去掉 stop 需要确认是否有这个必要。

// router.js
let routes = [
  {
   path: '/',
   alias: '/admin',
   component: Menu,
   children: [...Pages],
  },
  {
   path: '*',
   name: '404',
   component: NotFound,
  },
 ];

在路由中可以看到,Menu 是作为根路由进行渲染,除了 404 页面都是它的子路由,所以 stop 修饰符是没有必要加上的,去除后经过测试没有其他影响。

深入 element popover 源码分析原因

对 element 组件进行 debug 时,可以直接引入相关组件的源码

import ElPopover from 'element-ui/packages/popover';
export default {
  components: {
    CheckboxFilter,
    ElPopover
  },
  ...
}

然后我们就可以在node_modules的 element 源码进行 debug 操作(危险步骤,debug 后需要复原)。

// node_modules/element-ui/packages/popover/src/main.vue
mounted() {
  ...
  if (this.trigger === 'click') {
   on(reference, 'click', this.doToggle);
   on(document, 'click', this.handleDocumentClick);
  } else if (this.trigger === 'hover') {
   ...
  } else if (this.trigger === 'focus') {
   ...
  }
}

popover 在 mounted 钩子内初始化了trigger='click'的事件绑定,on(document, 'click', this.handleDocumentClick)这里绑定了 document 很可能就是阻止事件冒泡后不能触发外部点击隐藏的判断逻辑。

// node_modules/element-ui/packages/popover/src/main.vue
handleDocumentClick(e) {
 let reference = this.reference || this.$refs.reference;
 const popper = this.popper || this.$refs.popper;

 if (!reference && this.$slots.reference && this.$slots.reference[0]) {
  reference = this.referenceElm = this.$slots.reference[0].elm;
 }
 if (!this.$el ||
  !reference ||
  this.$el.contains(e.target) ||
  reference.contains(e.target) ||
  !popper ||
  popper.contains(e.target)) return;
 this.showPopper = false;
},

这里判断this.$el是否包含 click 的 target,从而是否触发this.showPopper = false,当菜单栏阻止事件冒泡后 document 不能监听到 click 事件,才会无法进行外部点击隐藏的判断逻辑。

延伸v-clickoutside

element 的 select 组件中用到了 v-clickoutside 自定义指令,作用和 popover 的 handleDocumentClick 差不多(倒不如说 handleDocumentClick 是特殊的 clickoutside)

在上面的问题中,我们单独把 v-clickoutside 抽出来使用确实可以的,这是为什么呢?

// node_modules/element-ui/packages/popover/src/utils/clickoutside.js
!Vue.prototype.$isServer && on(document, 'mousedown', e => (startClick = e));

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

答案是 v-clickoutside 使用鼠标事件判断的,所以 click 的 阻止冒泡不会让 clickoutside 无效。

总结

解决 bug 的过程中需要做到不产生额外的 bug,并且深入分析问题的原因有助于能力的提高。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery实现可横向和竖向展开的动态下滑菜单效果
Aug 24 Javascript
jquery实现浮动在网页右下角的彩票开奖公告窗口代码
Sep 04 Javascript
快速学习jQuery插件 jquery.validate.js表单验证插件使用方法
Dec 01 Javascript
javascript 定时器工作原理分析
Dec 03 Javascript
Bootstrap源码解读表单(2)
Dec 22 Javascript
纯原生js实现table表格的增删
Jan 05 Javascript
Jquery与Bootstrap实现后台管理页面增删改查功能示例
Jan 22 Javascript
Node.js对MongoDB数据库实现模糊查询的方法
May 03 Javascript
vue cli webpack中使用sass的方法
Feb 24 Javascript
JavaScript实现新年倒计时效果
Nov 17 Javascript
如何使用electron-builder及electron-updater给项目配置自动更新
Dec 24 Javascript
vue2.0中set添加属性后视图不能更新的解决办法
Feb 22 Javascript
JavaScript学习笔记之图片库案例分析
Jan 08 #Javascript
JavaScript学习笔记之DOM操作实例分析
Jan 08 #Javascript
vue单文件组件lint error自动fix与styleLint报错自动fix详解
Jan 08 #Javascript
说说如何在Vue.js中实现数字输入组件的方法
Jan 08 #Javascript
小试SVG之新手小白入门教程
Jan 08 #Javascript
vue组件通信传值操作示例
Jan 08 #Javascript
利用d3.js力导布局绘制资源拓扑图实例教程
Jan 08 #Javascript
You might like
PHP面向对象分析设计的经验原则
2008/09/20 PHP
php继承的一个应用
2011/09/06 PHP
PHP使用PHPMailer发送邮件的简单使用方法
2013/11/12 PHP
php密码生成类实例
2014/09/24 PHP
PHP实现绘制3D扇形统计图及图片缩放实例
2014/10/01 PHP
thinkphp循环结构用法实例
2014/11/24 PHP
在PHP中使用FastCGI解析漏洞及修复方案
2015/11/10 PHP
Zend Framework入门教程之Zend_Config组件用法详解
2016/12/09 PHP
ext combox 下拉框不出现自动提示,自动选中的解决方法
2010/02/24 Javascript
JavaScript 开发规范要求(图文并茂)
2010/06/11 Javascript
JavaScript高级程序设计(第3版)学习笔记4 js运算符和操作符
2012/10/11 Javascript
js实现单行文本向上滚动效果实例代码
2013/11/28 Javascript
使用jQuery实现的掷色子游戏动画效果
2014/03/14 Javascript
基于iframe实现类似于ajax的页面无刷新
2014/05/31 Javascript
AngularJs  Understanding Angular Templates
2016/09/02 Javascript
JavaScript学习笔记整理_简单实现枚举类型,扑克牌应用
2016/09/19 Javascript
微信小程序 后台https域名绑定和免费的https证书申请详解
2016/11/10 Javascript
微信小程序上滑加载下拉刷新(onscrollLower)分批加载数据(二)
2017/05/11 Javascript
vue v-model表单控件绑定详解
2017/05/17 Javascript
Node.js简单入门前传
2017/08/21 Javascript
基于JavaScript中字符串的match与replace方法(详解)
2017/12/04 Javascript
node将geojson转shp返回给前端的实现方法
2019/05/29 Javascript
[57:29]Alliance vs KG 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/17 DOTA
详解Python3中yield生成器的用法
2015/08/20 Python
Python使用django搭建web开发环境
2017/06/09 Python
Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例
2017/08/18 Python
python使用Pycharm创建一个Django项目
2018/03/05 Python
python2.7无法使用pip的解决方法(安装easy_install)
2018/04/03 Python
Python实现初始化不同的变量类型为空值
2020/06/02 Python
html5+css3之CSS中的布局与Header的实现
2014/11/21 HTML / CSS
使用html5 canvas绘制圆环动效
2019/06/03 HTML / CSS
Java程序员面试题
2016/09/27 面试题
小学国庆节活动方案策划书
2014/09/16 职场文书
2019年幼儿园管理条例范本!
2019/07/17 职场文书
创业计划书之婴幼儿游泳馆
2019/09/11 职场文书
解决numpy数组互换两行及赋值的问题
2021/04/17 Python