Vue中事件大致分为4类

  1. 自定义事件
  2. DOM事件
  3. 组件DOM事件
  4. 组件自定义事件

自定义事件主要由两部分组成

  1. 事件存储器
  2. 绑定事件,触发事件,解绑事件

Vue的每个实例都会有一个_events对象,用来存放本实例上注册的自定义事件,绑定自定义事件的大致流程如下

  1. this.$on 绑定事件
  2. this.$emit 触发事件
  3. this.$off 解绑事件

如果需要给组件绑定原生DOM事件,需要加上native这个修饰符。组件绑定的DOM事件,在父实例解析完毕才开始挂载,遇到子元素是组件,然后去解析内部并生成DOM之后才用addEventListener挂载。

绑定标签DOM事件

对标签绑定DOM事件,会生成如下的渲染函数

with(this) {return _c('div', {on: {click: function() {}}})
}

根据渲染函数,执行得到VNode,可以看到事件被放到了data上

{tag: 'div',data: {on: {click() {}}}
}

在template解析得到VNode之后,接下来就会进行DOM的生成和挂载,而绑定事件就是发生在开始挂载,创建DOM之后的阶段,挂载是从Vue.prototype._update开始的。绑定DOM事件核心方法就是updateDOMListeners

function updateDOMListeners(oldVnode, vnode) {  var on = vnode.data.on || {};    var oldOn = oldVnode.data.on || {};var target = vnode.elm;// 遍历绑定的事件for (name in on) {newHandler = on[name];oldHandler = oldOn[name];   // 没有旧事件,就直接添加新事件if (typeof oldHandler === "undefined") {// 给事件回调包装一层target.addEventListener(name, function(){on[name]() // 执行保存在vnode的事件});}        // 新事件和旧事件不一样,替换旧事件else if (newHandler !== oldHandler) {on[name] = newHandler;}}   // 移除旧事件for (name in oldOn) {   // 旧事件不存在新事件中,直接移除  if (typeof on[name] === "undefined") {target.removeEventListener(name, oldOn[name]);}}
}

自定义事件

Vue的自定义事件是存储在vm._events中,这个作为自定义事件的存储器。它是在_init时候就初始化了

Vue.prototype._init = function(options) {initEvents(vm);
}
function initEvents (vm) {vm._events = Object.create(null);
}

下面介绍自定义事件4个核心方法

  • $on
  • $off
  • $once
  • $emit
Vue.prototype.$on = function(event, fn) {var vm = this;// 判断传入的event是否为数组// 循环这个数组,给每一个event都绑定回调fnif (Array.isArray(event)) {        for (var i = 0,l = event.length; i < l; i++) {            this.$on(event[i], fn);}} else { // 如果不是数组,直接添加回调fn(vm._events[event] || (vm._events[event] = [])).push(fn);}    // 为了链式调用return vm
};
Vue.prototype.$once = function(event, fn) {var vm = this;     // 重新包装一下回调// 在回调内部触发$offfunction on() {vm.$off(event, on);fn.apply(vm, arguments);}on.fn = fn;vm.$on(event, on);// 为了链式调用return vm;
};
Vue.prototype.$emit = function(event) {  var vm = this;    var _events= event.toLowerCase();    var cbs = vm._events[_events]; if (cbs) {cbs = cbs.length > 1 ? toArray(cbs) : cbs; var args = toArray(arguments, 1);// 遍历回调,一个个调用for (var i = 0, l = cbs.length; i < l; i++) {cbs[i].apply(vm, args);}}    // 为了链式调用return vm
};
Vue.prototype.$off = function(event, fn) {   var vm = this;    if (!arguments.length) {vm._events = Object.create(null);        return vm}    // 递归调用if (Array.isArray(event)) {        for (var i = 0, l = event.length; i < l; i++) { this.$off(event[i], fn);}        return vm} var cbs = vm._events[event];    if (!cbs) return vm    if (!fn) {vm._events[event] = null;        return vm}    // 去掉特定的函数if (fn) {var cb;        var len = cbs.length;     // 遍历移除相应回调while (len--) {cb = cbs[len];            if (cb === fn || cb.fn === fn) {cbs.splice(len, 1);                break}}}    // 为了链式调用return vm
};

给组件绑定自定义事件

当我们给组件绑定自定义事件时,会生成这样的VNode

{tag: 'test',componentOptions: {listeners: {click($event) {}}}
}

注册自定义事件的核心方法就是updateComponentListeners

function updateComponentListeners(vm, listeners, oldListeners) {var name, cur, old;    for (name in listeners) {cur = listeners[name];old = oldListeners[name];   // 没有旧事件,就直接添加新事件if (typeof old === "undefined") {vm.$on(name, cur);}      // 新事件和旧事件不一样,替换旧事件else if (cur !== old) {on[name] = cur;}}    // 移除旧事件for (name in oldListeners) {        if (typeof listeners[name] === "undefined") {vm.$off(name, oldOn[name]);}}
}

它内部其实也是调用了,自定义事件的$on, $off

Vue Events模块原理分析相关推荐

  1. vue双向数据绑定原理分析--Mr.Ember

    vue双向数据绑定原理分析 摘要 vue常用,但原理常常不理解,下面我们来具体分析下vue的双向数据绑定原理. (1)创建一个vue对象,实现一个数据监听器observer,对所有数据对象属性进行监听 ...

  2. SE 注意力模块 原理分析与代码实现

    前言 本文介绍SE注意力模块,它是在SENet中提出的,SENet是ImageNet 2017的冠军模型:SE模块常常被用于CV模型中,能较有效提取模型精度,所以给大家介绍一下它的原理,设计思路,代码 ...

  3. ECA 注意力模块 原理分析与代码实现

    前言 本文介绍ECA注意力模块,它是在ECA-Net中提出的,ECA-Net是2020 CVPR中的论文:ECA模块可以被用于CV模型中,能提取模型精度,所以给大家介绍一下它的原理,设计思路,代码实现 ...

  4. 人体红外传感模块原理分析

    数字热释电传感器是将传统热释电传感器的敏感元与信号处理芯片集成化设计,将敏感元与 IC 芯片集成封装到传感器屏蔽罩内部,敏感元通过感应外界人体移动产生的红外信号,以差分输入的方式传送到高精度的数字智能 ...

  5. Vue中methods原理分析

    1. methods是如何绑定this的 methods绑定上下文执行环境是通过bind来进行的.固定了这个this.Vue考虑到不是所有的浏览器都支持bind.于是也实现了自己的polyfillBi ...

  6. 移动管家手机控车一键启动车载车联网模块原理分析与电路设计图解

    基于手机控制的智能小车的设计与实现:中山迈易科技研制手机控制汽车系统开发方案 智能汽车,远程启动不再为车内空调冬暧夏凉烦恼,实现了手机远程控制汽车.汽车无钥匙进入.一键启动.GSM/GPS车辆监控管理 ...

  7. vue实战 京东金融 1 项目设计与原理分析

    项目设计与原理分析 环境及知识准备 运行环境 构建环境 编辑器 基础知识 业务开发流程 技术选型 构建工具 MVVM框架选择 模块化设计 自适应方案设计 代码维护及复用性设计的思考 业务开发 测试验证 ...

  8. PCI Express解析——系列文章【4】:PCIe原理分析之——PCI Express系统模块、PCIe体系结构

    PCI Express解析--系列文章[4]:PCIe原理分析之--PCI Express系统模块.PCIe体系结构 2.3 PCI Express系统模块图 2.4 PCI Express体系结构 ...

  9. Vue数据绑定以及双向绑定原理分析

    效果 分析 已经了解到vue是通过数据劫持的方式来做数据绑定的,其中最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的,无疑这个方法是本文中最 ...

最新文章

  1. linux IP类常用命令
  2. Linux多任务编程——进程
  3. JAVA里面main找不到符号_java – 带有NBAndroid的NetBeans – 找不到符号setContentView(R.layout.main);...
  4. SharePoint 2013 InfoPath 无法保存下列表单
  5. js 里面的键盘事件对应的键码
  6. 条款33:避免遮掩继承而来的名称
  7. 总结-Linux基础指令
  8. 27岁到来之际,我在大厂实现了年薪40W+的小目标
  9. 分享一篇SCCM软件更新的故障排除
  10. AFA人工鱼群算法函数优化求解实例C++(2020.11.4)
  11. 自创RTSP 服务器 用多款客户端软件测试接入可以,唯独VLC接入不了
  12. java中将zip文件解压到指定目录下
  13. Echarts柱状图属性设置大全
  14. VelocityTracker 速度追踪
  15. html横向导航条代码动态伪类,伪类导航栏.html
  16. 微信群二维码活码生成源码
  17. Linux(CentOS 7)服务器增加固态硬盘作为系统盘
  18. c++语言生成一个随机数,C++ 快速随机数生成器
  19. iOS开发:上架的App生成二维码下载的方法
  20. linux系统下网络吞吐量/CPU占用率/流量控制的测试

热门文章

  1. educoder Git入门之分支管理
  2. python自动化测试培训脱产_柠檬班python自动化测试课程完整版
  3. 5月全球CTF比赛时间汇总来了!
  4. 离散时滞系统matlab仿真,离散混沌系统的Matlab仿真
  5. nginx如何替换ssl证书
  6. Feign原理:current list of Servers哪里来的
  7. 这是?国内跨境电商降本增收营销神器
  8. 因IP被列入黑名单导致U-Mail被退信的处理方法
  9. 【笔记】《iOS开发进阶-唐巧》
  10. php1050r210,parkerPARKESL parker维修PARKEROP-ETCATparker油管PARKESLV压力传感器