一个因@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 相关文章推荐
ASP.NET jQuery 实例12 通过使用jQuery validation插件简单实现用户注册页面验证功能
Feb 03 Javascript
javascript 使td内容不换行不撑开
Nov 29 Javascript
jquery等待效果示例
May 01 Javascript
js使用removeChild方法动态删除div元素
Aug 01 Javascript
BootStrap文件上传样式超好看【持续更新】
May 10 Javascript
node.js入门学习之url模块
Feb 25 Javascript
vue如何引用其他组件(css和js)
Apr 13 Javascript
微信小程序 登录的简单实现
Apr 19 Javascript
JS实现百度搜索接口及链接功能实例代码
Feb 02 Javascript
Auto.js自动收取自己和好友蚂蚁森林能量脚本
Jun 28 Javascript
实用Javascript调试技巧分享(小结)
Jun 18 Javascript
vue实现简易的双向数据绑定
Dec 29 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
深入掌握include_once与require_once的区别
2013/06/17 PHP
Thinkphp实现MySQL读写分离操作示例
2014/06/25 PHP
PHP实现上传多文件示例代码
2017/02/20 PHP
PHPExcel实现表格导出功能示例【带有多个工作sheet】
2018/06/13 PHP
ASP Json Parser修正版
2009/12/06 Javascript
JS、DOM和JQuery之间的关系示例分析
2014/04/09 Javascript
jQuery选择器源码解读(一):Sizzle方法
2015/03/31 Javascript
Bootstrap Paginator分页插件使用方法详解
2016/05/30 Javascript
基于Bootstrap实现tab标签切换效果
2020/04/15 Javascript
微信小程序 火车票查询实例讲解
2016/10/17 Javascript
详解jQuery中ajax.load()方法
2017/01/25 Javascript
详解如何用webpack4从零开始构建react开发环境
2019/01/27 Javascript
vuex 动态注册方法 registerModule的实现
2019/07/03 Javascript
vue-cli 为项目设置别名的方法
2019/10/15 Javascript
python定时采集摄像头图像上传ftp服务器功能实现
2013/12/23 Python
Python实现对PPT文件进行截图操作的方法
2015/04/28 Python
Python发送以整个文件夹的内容为附件的邮件的教程
2015/05/06 Python
分析Python中设计模式之Decorator装饰器模式的要点
2016/03/02 Python
Python中str.format()详解
2017/03/12 Python
PyTorch 随机数生成占用 CPU 过高的解决方法
2020/01/13 Python
Numpy中np.max的用法及np.maximum区别
2020/11/27 Python
python3实现简单飞机大战
2020/11/29 Python
python如何构建mock接口服务
2021/01/28 Python
Ellos丹麦:时尚和服装在线
2016/09/19 全球购物
法国珠宝店:CLEOR
2017/01/29 全球购物
卡西欧B级产品官方网站:Casio Outlet
2018/05/22 全球购物
C语言中一个结构不能包含指向自己的指针吗
2012/05/25 面试题
业务员岗位职责范本
2013/12/15 职场文书
商场中秋节活动方案
2014/02/07 职场文书
《莫高窟》教学反思
2014/02/25 职场文书
优秀团干部个人事迹
2014/05/29 职场文书
语文教育专业求职信
2014/06/28 职场文书
中学生自我评价2015
2015/03/03 职场文书
2015年度护士个人工作总结
2015/04/09 职场文书
诚信教育主题班会
2015/08/13 职场文书
用Python可视化新冠疫情数据
2022/01/18 Python