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

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

城市列表选择组件

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

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

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

第一步

输入框获取焦点后显示组件很简单,我们给输入框绑定焦点事件然后给组件传入一个显示的状态即可,我们把 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,进行这一步之后,我们的问题得到了解决,只要我们点击这个容器以外的地方就会隐藏城市列表组件,我以为算是结束了,不过那是不可能的,还是我太年轻了,这样做的后果就是不管我们点击任何一个地方它都会触发这个事件,即使是我们切换到其他组件时,事件照样会被触发,显然这个不是我们想要的,因为当前事件会被无限触发,无疑会给我们带来不可预见的问题。


我们需要的最好效果肯定是当前的全局事件就在当前的组件下产生作用,当我们切换到其他组件时,事件自动删除,于是我可能想到的就是利用 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 中如何绑定全局事件以及进行优化,一定要记住事件的绑定与解除哪里有一个大坑。

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

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


Vue一个案例引发的动态组件与全局事件绑定总结的更多相关文章

  1. Vue一个案例引发的递归组件的使用

    今天我们继续使用 Vue 的撸我们的实战项目,只有在实战中我们才会领悟更多,光纸上谈兵然并卵,继上篇我们的<Vue一个案例引发的动态组件与全局事件绑定总结> 之后,今天来聊一聊我们如何在项 ...

  2. Vue一个案例引发「内容分发slot」的最全总结

    今天我们继续来说说 Vue,目前一直在自学 Vue 然后也开始做一个项目实战,我一直认为在实战中去发现问题然后解决问题的学习方式是最好的,所以我在学习一些 Vue 的理论之后,就开始自己利用业余时间做 ...

  3. Vue一个案例引发「动画」的使用总结

    项目开发中动画有着很重要的作用,而且也是用到的地方非常多,例如:鼠标的进入离开,弹窗效果,组件的显示隐藏,列表的切换等等,可以说我们网页上的动画无处不在,也有人说了,这些东西也可以不使用动画. 对,你 ...

  4. jquery mobile Checkbox动态添加刷新及事件绑定

    jquery mobile Checkbox动态添加刷新及事件绑定 在微信项目中,涉及到一个多选功能.数据来自后台数据库,需要动态加载. 项目结构:微信api+web app.使用jquery mob ...

  5. React中,input外边如果包一个div,可以把input的onChange事件绑定到div上面,并且也生效

    最近第一次开始学习封装组件,遇到几个比较神奇的问题. 首先就是如果input外边包一个div,如果把input的onChange事件绑定到div上,也会生效 <div onChange={(e) ...

  6. 七、vue语法补充二(动态组件 & 异步组件、访问元素 & 组件、混入)

    1..sync 修饰符 2.3.0+ 新增 vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定.类似于v-model的效果 例子: this.$ ...

  7. vue 基础重要组件 模板指令 事件绑定

    组件:data methods watch new vue({ data:{ a:1, b:[] }, methods:{ dosomething:function(){ this.a++; } }, ...

  8. HTML中动态生成内容的事件绑定问题【转载】

    转自 http://www.hitoy.org/event-binding-problem-of-dynamically-generated-content.html 由于实际的需要,有时需要往网页中 ...

  9. 组件基础(参数校验和动态组件、v-once)—Vue学习笔记

    最最最后一点关于组件传值的问题. 提醒:本篇内容请使用Vue.js开发版!(附带完成的警告和提示) 1.组件的参数校验 父组件向子组件传值,子组件可以决定传值的一些限制. 比如,子组件指向接收Stri ...

随机推荐

  1. Codeforces 1220E. Tourism

    传送门 这是一道英语题,首先要读懂题目: $\text{Alex believes that his trip will be interesting only if he will not use ...

  2. Java Lock的使用

    + ReentrantLock类的使用 + ReentrantReadWriteLock类的使用 1. 使用ReentrantLock类 ReentrantLock类能够实现线程之间同步互斥,并且在扩 ...

  3. spring boot配置定时任务设置

    一.定时任务的时间写法: 每天凌晨2点  0 0 2 * * ?和每天隔一小时 0 * */1 * * ? 每隔5秒执行一次:*/5 * * * * ? 每隔5分执行一次:0 */5 * * * ? ...

  4. git配置ssh秘钥(公钥以及私钥)linux

    本文默认已经安装git,并有github或者gitlab账号 git在linux下安装参考:https://www.cnblogs.com/lz0925/p/10791147.html 在Linux中 ...

  5. 第十篇.5、python并发编程之协程

    一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...

  6. spring cloud eureka注册原理-注册失败填坑

    写在前面 我们知道Eureka分为两部分,Eureka Server和Eureka Client.Eureka Server充当注册中心的角色,Eureka Client相对于Eureka Serve ...

  7. 17JQuery高级

    1. 动画 1. 三种方式显示和隐藏元素 1. 默认显示和隐藏方式 1. show([speed,[easing],[fn]]) 1. 参数: 1. speed:动画的速度.三个预定义的值(" ...

  8. Memcached快速入门

    1.基本概念 基于高性能的key-value的内存数据库.单进程多线程,协议简单,使用文本行的协议,支持数据类型简单,不支持持久化,轻量级锁CAS机制,集群互不通信,缓存策略(LRU,FIFO,LFU ...

  9. python3之selenium.webdriver 库练习自动化谷歌浏览器打开百度自动百度关键字

    import os,time,threading from selenium import webdriver from selenium.webdriver.common.keys import K ...

  10. hdu3586 Information Disturbing[二分答案+树形DP]

    给定 n 个节点的树,边有权值.1 号点是根,除了 1 号点外的度数为 1 的节点是叶子.要求切断所有叶子和 1 号点之间的联系,切断一条边要花费这条边上权值对应的代价,要求总的代价不超过 m.在满足 ...