web前端开发个人技术博客
当前位置: 前端技术 > 一次Vue实践引发的动态组件与全局事件绑定的心得体会

一次Vue实践引发的动态组件与全局事件绑定的心得体会

2019-04-26 分类:前端技术 作者:码云 阅读(1378)

最近一直在苦心专研vue.js,相关书籍也是买了一大堆,边看边操作边实践,这是作为一个码农必备的精神。光看不动手实践也是不行的,这样只会让你停留在边缘层次,用一句俗语概括就是“光说不练假把式”。所以我们在学习一门新技术的时候必需要动手实践,只有在实战项目中才能发现问题,才能发现我们没有掌握的知识点,而后发现问题处理问题,我们的能力才能得以提升,要不然就有点眼高手低了。

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

城市列表选择组件

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

  • 输入框获取焦点时,显示组件
  • 点击城市列表更新输入框的城市显示
  • 点击其他空白处组件隐藏
  • 在切换到其他组件时,选择的城市保留而不是被重置
一次Vue实践引发的动态组件与全局事件绑定的心得体会

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

第一步

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

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

第二步

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

第三步

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

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

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

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

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

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

一次Vue实践引发的动态组件与全局事件绑定的心得体会

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

1
2
3
4
5
beforeDestroy() {
    document.removeEventListener("click", () => {
      //...
    });
}

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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该如何使用以及作用是什么呢?

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

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

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

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

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

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

1
2
3
4
5
6
activated() {
    document.addEventListener("click", this.isSearchCityNode);
},
deactivated() {
    document.removeEventListener("click", this.isSearchCityNode);
}

结束语

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

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

文中如有不足之处,欢迎大神拍砖!

对web开发技术感兴趣的同学,欢迎加入Q群:565733884,不论你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天升级视频资料。

最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。

「本文为原创文章,版权归码云笔记所有,欢迎分享本文,转载请保留出处!」

赞(15) 打赏

觉得文章有用就打赏一下文章作者

支付宝
微信
15

觉得文章有用就打赏一下文章作者

支付宝
微信

上一篇:

下一篇:

你可能感兴趣

共有 2 条评论 - 一次Vue实践引发的动态组件与全局事件绑定的心得体会

  1. 恩越 Linux Chrome 62.0.3202.84

    值得学习,谢谢

    1. 码云 Windows 7 Chrome 69.0.3497.100

      @恩越谢谢

博客简介

码云笔记: mybj123.com,一个关注Web前端开发技术的博客,主要记录和总结前端工作中常用的知识及我的生活。
更多博客详情请看关于博客

精彩评论