最近在自学 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. Linux-1.1root初始密码设置,切换root用户

    Ubuntu安装好后,root密码需要自己设置 root初始密码设置 sudo passwd root 权限不够时,切换root su 回车后输入密码 exit 退出登录的账户

  2. ITCAST-C# 委托

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace _12委 ...

  3. Linux cat命令详解(连接文件并打印到标准输出设备上)

    cat:连接文件并打印到标准输出设备上 一.命令格式: cat [-AbeEnstTuv] [--help] [--version] filename 二.参数说明: -n 或 --number:由 ...

  4. 北京化妆时尚气息自适应CSS例子

    三里屯太古广场——北京化妆时尚气息的先锋阵地! “乐色起义”创意化妆设计大赛——国内最具创意的公益设计大赛! CNature——国内最具个性的时尚环保公益组织! 一个多么奇妙的组合!就在2010年的这 ...

  5. java apache-commons-collections中Map辅助类的使用

    前言 apache-commons-collections中Map辅助类,很是有用.尽管我们通过原生Map经过业务逻辑处理也能达到相同的作用与效果,但毕竟作为一个开源的工具类辅助类,对它有个了解还是有 ...

  6. 三种Shell脚本编程中避免SFTP输入密码的方法

    最近编程中用到sftp上传文件,且需要用crontab预设定时上传事件.而sftp不同于ftp,没有提供选项如 -i 可以将密码直接编码进程序.使用sftp指令,会自动请求用户输入密码. 总结一下可以 ...

  7. HackIM web关writeup

    Web100 访问页面将看到下面的错误 在burp里使用request / response查看有没有什么不正常的地方.如下图所示,在返回的数据包里被设置了两次不同的PHPSESSID. 如果我把PH ...

  8. golang连接activemq,发送接收数据

    介绍 使用golang连接activemq发送数据的话,需要使用一个叫做stomp的包,直接go get github.com/go-stomp/stomp即可 代码 生产者 package main ...

  9. Python测试开发必知必会-PEP

    互联网发展了许多年,不仅颠覆了很多行业,还让很多职位有了更多的用武之地.产品发布迭代速度不断加快,让测试开发这个岗位简直火得不要不要的. Python语言,作为一种更接近人来自然语言的开发语言,以简洁 ...

  10. 认识配置文件schema.xml(managed-schema)

    1.schema文件是在SolrConfig中的架构工厂定义,有两种定义模式: 1.1.默认的托管模式: solr默认使用的就是托管模式.也就是当在solrconfig.xml文件中没有显式声明< ...