vue原理分析(十)研究new Vue()中的initEvents

在Vue.prototype._init 中有一些init函数,今天我们来研究这些init函数

Vue.prototype._init = function (options) {......{initProxy(vm);}......initLifecycle(vm);initEvents(vm);initRender(vm);callHook$1(vm, 'beforeCreate', undefined, false /* setContext */);initInjections(vm); // resolve injections before data/propsinitState(vm);initProvide(vm); // resolve provide after data/propscallHook$1(vm, 'created');......
}

上一篇中已经研究了initLifecycle,今天我们往下研究

Vue.prototype._init = function (options) {......initEvents(vm);......
}

看下源码 initEvents(vm);

function initEvents(vm) {vm._events = Object.create(null);vm._hasHookEvent = false;// init parent attached eventsconst listeners = vm.$options._parentListeners;if (listeners) {updateComponentListeners(vm, listeners);}
}
vm._events = Object.create(null);

该行代码创建了一个原型为null的空对象,并将这个对象赋值给vm实例的_events属性

vm._hasHookEvent = false;

该行代码 给vm实例的_hasHookEvent属性赋值为false

const listeners = vm.$options._parentListeners;

从英文注释,我们可以知道这行代码是为了初始化父组件添加的事件

因为是取的组件$options属性的_parentListeners,这个比较复杂,涉及到双向绑定和虚拟dom,我们后续研究,先暂时理解为父组件绑定在当前组件上的事件

如果存在事件listeners

则执行下面这段代码

if (listeners) {updateComponentListeners(vm, listeners)
}
function updateComponentListeners(vm, listeners, oldListeners) {target$1 = vm;updateListeners(listeners, oldListeners || {}, add$1, remove$1, createOnceHandler$1, vm);target$1 = undefined;
}
target$1 = vm;

这行代码的主要作用是保留对vm实例的引用

updateListeners(listeners, oldListeners || {}, add, remove, vm)

这行代码执行updateListeners方法

function add$1(event, fn) {target$1.$on(event, fn);
}
function remove$1(event, fn) {target$1.$off(event, fn);
}

涉及到 target$1.$on 和 target$1.$off

Vue.prototype.$on = function (event, fn) {const vm = this;if (isArray(event)) {for (let i = 0, l = event.length; i < l; i++) {vm.$on(event[i], fn);}}else {(vm._events[event] || (vm._events[event] = [])).push(fn);// optimize hook:event cost by using a boolean flag marked at registration// instead of a hash lookupif (hookRE.test(event)) {vm._hasHookEvent = true;}}return vm;
};

else之前的代码都很简单,先缓存this,如果传入的事件是事件数组的话,则分别对数组内的每一项调用$on绑定事件

else之前的代码 如果event不是个数组,给vm._events[event]传入fn函数

if (hookRE.test(event)) {vm._hasHookEvent = true;
}

它表示的是父组件有没有直接绑定钩子函数在当前组件上

return vm

最后 返回vm实例对象

现在我们知道了vm.$on方法主要就是把传入的方法给push到_events属性里,方便之后被$emit调用

Vue.prototype.$off = function (event, fn) {const vm = this;// allif (!arguments.length) {vm._events = Object.create(null);return vm;}// array of eventsif (isArray(event)) {for (let i = 0, l = event.length; i < l; i++) {vm.$off(event[i], fn);}return vm;}// specific eventconst cbs = vm._events[event];if (!cbs) {return vm;}if (!fn) {vm._events[event] = null;return vm;}// specific handlerlet cb;let i = cbs.length;while (i--) {cb = cbs[i];if (cb === fn || cb.fn === fn) {cbs.splice(i, 1);break;}}return vm;
};
const vm = this;
// all
if (!arguments.length) {vm._events = Object.create(null);return vm;
}

从代码我们看出来当arguments.length为0的时候,说明没有任何参数,这时就需要移除所有的事件监听器,因此我们重置了 vm.events 属性。

// array of events
if (isArray(event)) {for (let i = 0, l = event.length; i < l; i++) {vm.$off(event[i], fn);}return vm;
}

如果参数event是个数组,则循环调用vm.$off

分析特殊情况

const cbs = vm._events[event];
if (!cbs) {return vm;
}
if (!fn) {vm._events[event] = null;return vm;
}

表示,有event但是没有cbs,没有callbacks,没有回调函数

则vm._events[event] = null,返回vm实例对象

let cb;
let i = cbs.length;
while (i--) {cb = cbs[i];if (cb === fn || cb.fn === fn) {cbs.splice(i, 1);break;}
}
return vm;

事件名和回调都有,从从列表中找到与参数提供回调函数相同的那个函数,并将它从列表中移除

再回到updateListeners方法

function updateListeners(on, oldOn, add, remove, createOnceHandler, vm) {let name, cur, old, event;for (name in on) {cur = on[name];old = oldOn[name];event = normalizeEvent(name);if (isUndef(cur)) {warn$2(`Invalid handler for event "${event.name}": got ` + String(cur), vm);}else if (isUndef(old)) {if (isUndef(cur.fns)) {cur = on[name] = createFnInvoker(cur, vm);}if (isTrue(event.once)) {cur = on[name] = createOnceHandler(event.name, cur, event.capture);}add(event.name, cur, event.capture, event.passive, event.params);}else if (cur !== old) {old.fns = cur;on[name] = old;}}for (name in oldOn) {if (isUndef(on[name])) {event = normalizeEvent(name);remove(event.name, oldOn[name], event.capture);}}
}
for (name in on) {cur = on[name];old = oldOn[name];event = normalizeEvent(name);if (isUndef(cur)) {warn$2(`Invalid handler for event "${event.name}": got ` + String(cur), vm);}else if (isUndef(old)) {if (isUndef(cur.fns)) {cur = on[name] = createFnInvoker(cur, vm);}if (isTrue(event.once)) {cur = on[name] = createOnceHandler(event.name, cur, event.capture);}add(event.name, cur, event.capture, event.passive, event.params);}else if (cur !== old) {old.fns = cur;on[name] = old;}
}

遍历on中对象

如果on[name]未定义,则调用警告warn$2

如果oldOn[name]未定义,如果原事件 没有定义,则调用 createFnInvoker() 进行定义;但如果是一个 .once 修饰的事件,则会用 createOnceHandler() 重新定义该事件;最后将其添加到当前实例的 $on 属性中

如果on[name]与oldOn[name]不一致,将原事件定义的 函数定义部分 重新指向为当前新的事件定义,并赋值给新事件对象中

for (name in oldOn) {if (isUndef(on[name])) {event = normalizeEvent(name);remove(event.name, oldOn[name], event.capture);}
}

遍历oldOn中对象,将不存在于新事件对象中的事件去除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/52686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GeoTools解析GeoJson为要素集(FeatureCollection)含嵌套数组属性

Repository - Sonatype Nexus Repository <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

TypeScript 扩展

扩展 ?:可选参数 可选链事实上并不是TypeScript独有的特性&#xff0c;它是ES11&#xff08;ES2020&#xff09;中增加的特性 可选链使用可选链操作符 ? 作用是当对象的属性不存在时&#xff0c;会短路&#xff0c;直接返回undefined&#xff0c;如果存在&#xff0c;那么…

SpringCloud集成ELK

1、添加依赖 <dependency><groupId>net.logstash.logback</groupId><artifactId>logstash-logback-encoder</artifactId><version>6.1</version> </dependency>2、在logback-spring.xml中添加配置信息&#xff08;logback-sp…

Android SystemUI组件(06)导航栏创建分析虚拟按键

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧SystemBars分析中导航栏部分即可。 1 导航栏创建之makeStatusBarView 通过上一篇文章的…

前端 + 接口请求实现 vue 动态路由

前端 接口请求实现 vue 动态路由 在 Vue 应用中&#xff0c;通过前端结合后端接口请求来实现动态路由是一种常见且有效的权限控制方案。这种方法允许前端根据用户的角色和权限&#xff0c;动态生成和加载路由&#xff0c;而不是在应用启动时就固定所有的路由配置。 实现原理…

el-tree父子不互相关联时,手动实现全选、反选、子级全选、清空功能

el-tree父子不互相关联时&#xff0c;手动实现全选、反选、子级全选、清空功能 1、功能实现图示 2、实现思路 当属性check-strictly为true时&#xff0c;父子节点不互相关联&#xff0c;如果需要全部选中或选择某一节点下的全部节点就必须手动选择每个节点&#xff0c;十分麻…

【mysql】逻辑运算符

逻辑运算符 逻辑运算符主要是为了判断表达式的真假,返回结果也是1,0,null OR 这里面或就是两个条件或的关系,比如我要department_id等于10和等于20的情况就可以使用或. SELECT last_name,salary,department_id FROM employees WHERE department_id10 OR department_id20 …

区块链BCS配置选择注意事项

在配置区块链BCS&#xff08;Blockchain Service&#xff09;时&#xff0c;需要注意多个方面的细节以确保区块链网络的稳定、安全和高效运行。以下是从多个维度详细分析区块链BCS配置选择的注意事项&#xff0c;旨在为企业提供有价值的参考和指导。 一、基础配置注意事项 环…

CTF——简单的《WEB》

文章目录 一、WEB1、easysql2、baby_web3、baby_sql4、upload_easy5、easygame拓展1.1拓展1.2 6、ht_ssti7、包容乃大 一、WEB 1、easysql 题目描述&#xff1a; sql注入漏洞 1.常用的sql注入测试语句 2.sql注入bypass 解题思路 这边提示基本给的也很完整的&#xff0c;不…

C++开发基础之理解 CUDA 编译配置:`compute_XX` 和 `sm_XX` 的作用

前言 在 CUDA 编程中&#xff0c;确保代码能够在不同的 NVIDIA GPU 上高效运行是非常重要的。为了实现这一点&#xff0c;CUDA 编译器 (nvcc) 提供了多种配置选项&#xff0c;其中 compute_XX 和 sm_XX 是两个关键的编译选项。本文将深入探讨这两个选项的作用及其配置顺序&…

2398. 预算内的最多机器人数目(24.9.13)

题目 有n个机器人&#xff0c;给定两个下标从 0 开始的整数数组chargeTimes和runningCosts&#xff0c;两者长度都为(n)。第(i)个机器人充电时间为chargeTimes[i]单位时间&#xff0c;花费runningCosts[i]单位时间运行。另外还有一个整数budget。 运行(k)个机器人总开销是max…

大一新生以此篇开启你的算法之路

各位大一计算机萌新们&#xff0c;你们好&#xff0c;本篇博客会带领大家进行算法入门&#xff0c;给各位大一萌新答疑解惑。博客文章略长&#xff0c;可根据自己的需要观看&#xff0c;在博客中会有给大一萌新问题的解答&#xff0c;请不要错过。 入门简介&#xff1a; 算法…

可信的人类与人工智能协作:基于人类反馈和物理知识的安全自主驾驶强化学习

可信的人类与人工智能协作&#xff1a;基于人类反馈和物理知识的安全自主驾驶强化学习 Abstract 在自动驾驶领域&#xff0c;开发安全且可信赖的自动驾驶策略仍然是一项重大挑战。近年来&#xff0c;结合人类反馈的强化学习&#xff08;RLHF&#xff09;因其提升训练安全性和…

中国银河资产笔试25届考什么?如何通过考试|附真题库面试攻略

嘿&#xff0c;各位小伙伴们&#xff01;我是职小豚&#xff0c;今天就带大家一起探秘中国银河资产 25 届秋招&#xff0c;为大家揭开这场金融之旅的神秘面纱。 一、中国银河资产介绍 中国银河资产&#xff0c;那可是金融领域的璀璨巨星&#xff01;它就像一座闪耀着智慧光芒…

unity安装配置和vs2022联动教程

目录 1.选择vs2022配置 2.安装unity 2.1安装unity hub 2.2注册个人账号 2.3安装编辑器 2.4修改为简体中文 2.5添加许可证 2.6安装位置修改 3.项目的创建 3.1如何创建 3.2如何选择 3.3配置语言 3.4去哪里找语言包 4.unity编辑器窗口的介绍 4.1游戏的运行和停止 4…

日志中使用awk提取信息

订单发货-----------------express_code:ZTO-e xpress:中通速递-orderIDs:21782028-tradeNo:XD240822000089-storage:菜鸟仓&#xff08;武汉&#xff09;-nums:1 现在需要提取出 nums:后面的值用于排查问题 echo "storage:菜鸟仓&#xff08;武汉&#xff09;-nums:2&q…

11、Hive+Spark数仓环境准备

1、 Hive安装部署 1&#xff09;把hive-3.1.3.tar.gz上传到linux的/opt/software目录下 2&#xff09;解压hive-3.1.3.tar.gz到/opt/module/目录下面 [shuidihadoop102 module]$ tar -zxvf /opt/software/hive-3.1.3.tar.gz -C /opt/module/ 3&#xff09;修改hive-3.1.3-b…

《深度学习》深度学习 框架、流程解析、动态展示及推导

目录 一、深度学习 1、什么是深度学习 2、特点 3、神经网络构造 1&#xff09;单层神经元 • 推导 • 示例 2&#xff09;多层神经网络 3&#xff09;小结 4、感知器 神经网络的本质 5、多层感知器 6、动态图像示例 1&#xff09;一个神经元 相当于下列状态&…

安卓开发板_联发科MTK开发评估套件串口调试

串口调试 如果正在进行lk(little kernel ) 或内核开发&#xff0c;USB 串口适配器&#xff08; USB 转串口 TTL 适配器的简称&#xff09;对于检查系统启动日志非常有用&#xff0c;特别是在没有图形桌面显示的情况下。 1.选购适配器 常用的许多 USB 转串口的适配器&#xf…

Unstructured cannot write mode RGBA as JPEG 错误解决

Unstructured cannot write mode RGBA as JPEG 错误解决 0. 错误详细1. 解决方法 0. 错误详细 Image Extraction Error: Skipping the failed image Traceback (most recent call last):File "/root/miniconda3/envs/learn-yolo/lib/python3.11/site-packages/PIL/JpegIm…