Vue一个案例引起的动态组件与全局事件绑定总结

技术这东西真的不能光靠看,看是没有的,你必需要动手实践,只有在实战项目中才能发现问题,才能发现咱们没有掌握的知识点,而后发现问题解决问题,咱们的能力才能得以提高,要否则就有点眼高手低了。缓存

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

城市列表选择组件

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

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

下面咱们就一步一步的来拆解优化

第一步

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

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

第二步

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

第三步

须要咱们去点击其余地方城市组件被隐藏,有些同窗的第一印象多是利用 input 的 blur 事件(就是失去焦点事件),只要咱们的 input 失去焦点时,咱们就隐藏。spa

其实个人第一印象也是如此,可是咱们绑定的是 input 的失去焦点事件之后,当咱们选择城市列表的时候也是 input 失去焦点的时候,因此咱们就没法选取城市。显然这种思路是不行的。code

因此这里咱们只能去用到 Vue 的全局事件的绑定,而后去进行一个判断咱们点击的节点是哪里,若是是城市组件之外咱们就进行隐藏操做。component

咱们在 mounted 钩子函数中,进行以下操做。blog

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

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

咱们须要的最好效果确定是当前的全局事件就在当前的组件下产生做用,当咱们切换到其余组件时,事件自动删除,因而我可能想到的就是利用 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>

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

可是当咱们使用 的时候,咱们的 beforeDestroy 钩子函数就会失效,致使咱们第三步的全局事件的解绑就不能执行了,缘由是咱们的组件是被缓存起来,并无被销毁。天然会失效,可是咱们并不慌,当咱们使用 时,activated 和 deactivated 两个钩子函数被触发。

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

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

因此咱们不难发现,咱们彻底可使用这两个钩子去实现咱们全局事件的绑定与解绑,简直完美。

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

总结

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

咱们经过 能够建立一个能够缓存的组件,并且会新增两个钩子函数提供咱们使用

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

原文连接:https://www.jianshu.com/p/e7c...

相关文章
相关标签/搜索