一个因@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 相关文章推荐
JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型
Oct 11 Javascript
js 得到文件后缀(通过正则实现)
Jul 08 Javascript
jquery获取div距离窗口和父级dv的距离示例
Oct 10 Javascript
28个常用JavaScript方法集锦
Jan 14 Javascript
jQuery实现鼠标悬停显示提示信息窗口的方法
Apr 30 Javascript
快速使用node.js进行web开发详解
Apr 26 Javascript
详解Vue-cli代理解决跨域问题
Sep 27 Javascript
Angular表格神器ui-grid应用详解
Sep 29 Javascript
Node.js实现发送邮件功能
Nov 06 Javascript
layer弹出层倒计时关闭的实现方法
Sep 27 Javascript
基于vue--key值的特殊用处详解
Jul 31 Javascript
vue 获取到数据但却渲染不到页面上的解决方法
Nov 19 Vue.js
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
ASP和PHP都是可以删除自身的
2007/04/09 PHP
DW中链接mysql数据库时,建立字符集中文出现乱码的解决方法
2010/03/27 PHP
php实现的太平洋时间和北京时间互转的自定义函数分享
2014/08/19 PHP
解决PHP上传非标准格式的图片pjpeg失败的方法
2017/03/12 PHP
PHP编程获取图片的主色调的方法【基于Imagick扩展】
2017/08/02 PHP
Mac系统下安装PHP Xdebug
2018/03/30 PHP
自适应图片大小的弹出窗口
2006/07/27 Javascript
关于Jqzoom的使用心得 jquery放大镜效果插件
2010/04/12 Javascript
hover的用法及live的用法介绍(鼠标悬停效果)
2013/03/29 Javascript
Javascript 多浏览器兼容总结(实战经验)
2013/10/30 Javascript
深入解析JavaScript框架Backbone.js中的事件机制
2016/02/14 Javascript
老生常谈Bootstrap媒体对象
2017/07/06 Javascript
Angular 2 利用Router事件和Title实现动态页面标题的方法
2017/08/23 Javascript
KOA+egg.js集成kafka消息队列的示例
2018/11/09 Javascript
详解IOS微信上Vue单页面应用JSSDK签名失败解决方案
2018/11/14 Javascript
JavaScript实现选项卡效果的分析及步骤
2019/04/16 Javascript
vue项目中mock.js的使用及基本用法
2019/05/22 Javascript
Javascript地址引用代码实例解析
2020/02/25 Javascript
python中字符串前面加r的作用
2015/06/04 Python
python制作爬虫并将抓取结果保存到excel中
2016/04/06 Python
Python实现曲线拟合操作示例【基于numpy,scipy,matplotlib库】
2018/07/12 Python
Python实现E-Mail收集插件实例教程
2019/02/06 Python
Django学习笔记之为Model添加Action
2019/04/30 Python
python实现海螺图片的方法示例
2019/05/12 Python
python中lower函数实现方法及用法讲解
2020/12/23 Python
matplotlib之多边形选区(PolygonSelector)的使用
2021/02/24 Python
介绍一下gcc特性
2012/01/20 面试题
竞聘书格式及范文
2014/03/31 职场文书
5s推行计划书
2014/05/06 职场文书
医务人员医德考评自我评价
2015/03/03 职场文书
学历证明范文
2015/06/16 职场文书
2015年城管执法工作总结
2015/07/23 职场文书
职场新人知识:如何制定一份合理的工作计划?
2019/09/11 职场文书
两行代码解决Jupyter Notebook中文不能显示的问题
2021/04/24 Python
Python实现Hash算法
2022/03/18 Python
Python闭包的定义和使用方法
2022/04/11 Python