详解Vue 动态组件与全局事件绑定总结


Posted in Javascript onNovember 11, 2018

最近在自学 Vue 也了解了一些基本用法,也记录了一些笔记有兴趣的朋友可以去查看我的其他文章,技术这东西真的不能光靠看,看是没有的,你必须要动手实践,只有在实战项目中才能发现问题,才能发现我们没有掌握的知识点,然后发现问题解决问题,我们的能力才能得以提升,要不然就有点眼高手低了。

基于这个想法于是就开始自己去撸了一个旅游网站,旅游网站嘛避免不了城市的选择,所以在实现城市选择列表的时候碰到的一些问题,以及解决办法今天就记录下来做一个总结。

城市列表选择组件

首先说说我们要实现一个什么样的城市选择组件:

  • 输入框获取焦点时,显示组件
  • 点击城市列表更新输入框的城市显示
  • 点击其他空白处组件隐藏
  • 在切换到其他组件时,选择的城市保留而不是被重置

详解Vue 动态组件与全局事件绑定总结

下面我们就一步一步的来拆解

第一步

输入框获取焦点后显示组件很简单,我们给输入框绑定焦点事件然后给组件传入一个显示的状态即可,我们把 isShowCityList 传递给城市选择组件控制行为。

<el-input 
  @focus="isShowCityList=true"
  placeholder="请输入目的地">
</el-input>

第二步

我们也不做过多的表述本文想更多的是介绍动态组件与全局事件的绑定,利用的是子组件给父组件利用自定义事件 $emit 传给父组件。

第三步

需要我们去点击其他地方城市组件被隐藏,有些同学的第一印象可能是利用 input 的 blur 事件(就是失去焦点事件),只要我们的 input 失去焦点时,我们就隐藏。

其实我的第一印象也是如此,但是我们绑定的是 input 的失去焦点事件以后,当我们选择城市列表的时候也是 input 失去焦点的时候,所以我们就无法选取城市。显然这种思路是不行的。

所以这里我们只能去用到 Vue 的全局事件的绑定,然后去进行一个判断我们点击的节点是哪里,如果是城市组件以外我们就进行隐藏操作。

我们在 mounted 钩子函数中,进行如下操作。

mounted() {
  document.addEventListener("click", e => {
    console.log('全局事件被触发');
    if (!this.$refs.searchCity.contains(e.target)) {
      this.isLoadCityList = false;
    }
  });
}

OK,进行这一步之后,我们的问题得到了解决,只要我们点击这个容器以外的地方就会隐藏城市列表组件,我以为算是结束了,不过那是不可能的,还是我太年轻了,这样做的后果就是不管我们点击任何一个地方它都会触发这个事件,即使是我们切换到其他组件时,事件照样会被触发,显然这个不是我们想要的,因为当前事件会被无限触发,无疑会给我们带来不可预见的问题。

详解Vue 动态组件与全局事件绑定总结

我们需要的最好效果肯定是当前的全局事件就在当前的组件下产生作用,当我们切换到其他组件时,事件自动删除,于是我可能想到的就是利用 beforeDestroy 钩子函数去删除这个全局事件。也就是当我们切换到其他组件时,去删除这个全局事件。

beforeDestroy() {
  document.removeEventListener("click", () => {
   //...
  });
}

你以为这样我还就能解决问题了吗?显然还是不能,还是太年轻,只是这样我们是解除不了绑定的事件,那我们该怎么办呢?其实这里面有一个坑,大坑,因为这个大坑自己不知道,差了许多资料也没查出来,因为差的思路错了,最后在一个群里问了一个大佬,才得出答案,不得不说与前辈交流很重要啊,能帮你少踩很多坑。

这里如果想要解除绑定,解除和绑定的两个回调函数必须一致,什么意思呢?看代码你就明白。如果不这么操作,你是解除不掉事件的,至于更深的原因我也不怎么明白了,以后再去查阅一些资料。

methods: {
 isSearchCityNode(e) {
  if (!this.$refs.searchCity.contains(e.target)) {
   console.log("全局事件被触发");
   this.isLoadCityList = false;
  }
 } 
},
mounted() {
  document.addEventListener("click", this.isSearchCityNode);
},
beforeDestroy() {
  document.removeEventListener("click", this.isSearchCityNode);
}

第四步

需要我们在切换组件的时候保留我们选择的城市,如果不保留我们每次切换到其他组件时,我们选择的城市都会被重置为默认值,这个体验肯定是肯差的,也不是我们想要的。

被重置的原因则是我们在每次在不同的组件进行切换的时候,组件都会进行新建与销毁,这也会导致重复渲染问题对性能也是不友好的。

那么我们该如何去处理这个问题呢? 我这里使用了 keep-alive 去解决这个问题,那么 keep-alive 该如何使用以及作用是什么呢?

<keep-alive>
 <component v-bind:is="currentTabComponent"></component>
</keep-alive>

<keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们,它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。

但是当我们使用 <keep-alive> 的时候,我们的 beforeDestroy 钩子函数就会失效,导致我们第三步的全局事件的解绑就不能执行了,原因是我们的组件是被缓存起来,并没有被销毁。自然会失效,但是我们并不慌,当我们使用 <keep-alive> 时,activated 和 deactivated 两个钩子函数被触发。

activated:keep-alive 组件激活时调用。

deactivated:keep-alive 组件停用时调用。

所以我们不难发现,我们完全可以使用这两个钩子去实现我们全局事件的绑定与解绑,简直完美。

activated() {
  document.addEventListener("click", this.isSearchCityNode);
},
deactivated() {
  document.removeEventListener("click", this.isSearchCityNode);
}

总结

通过一个城市列表组件的案例,介绍了我们在 Vue 中如何绑定全局事件以及进行优化,一定要记住事件的绑定与解除哪里有一个大坑。

我们通过 <keep-alive> 可以创建一个可以缓存的组件,而且会新增两个钩子函数提供我们使用

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

Javascript 相关文章推荐
jquery事件机制扩展插件 jquery鼠标右键事件。
Dec 26 Javascript
ASP.NET jQuery 实例5 (显示CheckBoxList成员选中的内容)
Jan 13 Javascript
jQuery 联动日历实现代码
May 31 Javascript
jquery $.trim()方法使用介绍
May 21 Javascript
一个JavaScript递归实现反转数组字符串的实例
Oct 14 Javascript
js随机生成26个大小写字母
Feb 12 Javascript
jQuery树形插件jquery.simpleTree.js用法分析
Sep 05 Javascript
ES6扩展运算符的用途实例详解
Aug 20 Javascript
JS数组Object.keys()方法的使用示例
Jun 05 Javascript
什么时候不能在 Node.js 中使用 Lock Files
Jun 24 Javascript
详解Vuex下Store的模块化拆分实践
Jul 31 Javascript
VUE实现强制渲染,强制更新
Oct 29 Javascript
详解如何在vue项目中使用eslint+prettier格式化代码
Nov 10 #Javascript
AngularJS上传文件的示例代码
Nov 10 #Javascript
详解vue-cli 3.0 build包太大导致首屏过长的解决方案
Nov 10 #Javascript
优雅的在React项目中使用Redux的方法
Nov 10 #Javascript
Vue组件之单向数据流的解决方法
Nov 10 #Javascript
详解如何制作并发布一个vue的组件的npm包
Nov 10 #Javascript
如何在基于vue-cli的项目自定义打包环境
Nov 10 #Javascript
You might like
咖啡是不是喝了会上瘾?咖啡是必须品吗!
2021/03/04 新手入门
一个php作的文本留言本的例子(二)
2006/10/09 PHP
PHP 加密/解密函数 dencrypt(动态密文,带压缩功能,支持中文)
2009/01/30 PHP
smarty模板引擎从配置文件中获取数据的方法
2015/01/22 PHP
ExtJs事件机制基本代码模型和流程解析
2010/10/24 Javascript
FullCalendar日历插件应用之数据展现(一)
2015/12/23 Javascript
jQuery使用zTree插件实现树形菜单和异步加载
2016/02/25 Javascript
Boostrap模态窗口的学习小结
2016/03/28 Javascript
node.js利用redis数据库缓存数据的方法
2017/03/01 Javascript
nodejs multer实现文件上传与下载
2017/05/10 NodeJs
javascript 中iframe高度自适应(同域)实例详解
2017/05/16 Javascript
BootStrap给table表格的每一行添加一个按钮事件
2017/09/07 Javascript
前端MVVM框架解析之双向绑定
2018/01/24 Javascript
微信小程序项目总结之点赞 删除列表 分享功能
2018/06/25 Javascript
微信小程序支付PHP代码
2018/08/23 Javascript
Vue 2.0双向绑定原理的实现方法
2019/10/23 Javascript
微信小程序自定义模态弹窗组件详解
2019/12/24 Javascript
vue项目中使用eslint+prettier规范与检查代码的方法
2020/01/16 Javascript
vue使用better-scroll实现滑动以及左右联动
2020/06/30 Javascript
解决VUEX的mapState/...mapState等取值问题
2020/07/24 Javascript
Vue-cli打包后部署到子目录下的路径问题说明
2020/09/02 Javascript
解决Vue大括号字符换行踩的坑
2020/11/09 Javascript
[02:56]DOTA2矮人直升机 英雄基础教程
2013/11/26 DOTA
Python爬取网易云音乐上评论火爆的歌曲
2017/01/19 Python
Python实现读取txt文件并转换为excel的方法示例
2018/05/17 Python
python3.6+django2.0+mysql搭建网站过程详解
2019/07/24 Python
Python函数式编程指南:对生成器全面讲解
2019/11/19 Python
Pytorch数据拼接与拆分操作实现图解
2020/04/30 Python
python让函数不返回结果的方法
2020/06/22 Python
耐克中国官方商城:Nike中国
2018/10/18 全球购物
Ruby中的保护方法和私有方法与一般面向对象程序设计语言的一样吗
2013/05/01 面试题
学校七一活动方案
2014/01/19 职场文书
优秀党员个人总结
2015/02/14 职场文书
放假通知怎么写
2015/08/18 职场文书
mysql的MVCC多版本并发控制的实现
2021/04/14 MySQL
react中的DOM操作实现
2021/06/30 Javascript