Vue深入学习4—指令和生命周期

1.Vue是怎么识别 v- 指令的?

首先将HTML结构解析成属性列表,存入到数组中,接着遍历数组中的每一个节点,获取到不同指令对应的方法。

// 将HTML看作真正的属性列表
var ndoeAttrs = node.attributes;
var self = this;
// 类数组对象变为数组,一层一层的遍历节点
[].slice.call(nodeAttes).forEach(attr => {// 这里开始分析指令var attrName = attr.name;var value = attr.value;// 指令都是 v- 开头的var dir = attrName.substring(2);if(attrName.indexOf('v-') == 0){// v-下不同的指令if(dir == 'model'){// console.log('发现了model指令',value);// 添加Watchernew Watcher(self.$vue, value, value => {node.value = value;});// 得到 v 的值var v = self.getVueVal(self.$vue, value);// 显示 v 的值node.value = v;// 添加监听事件,基本实现双向绑定node.addEventListener('input', e => {var newVal = e.target.value;self.setVueVal(self.$vue, value, newVal);v = newVal;});}else if(dir == 'if'){// console.log('发现了if指令',value);}} 
})

2.v-model底层是怎么实现的?

v-model 会把关联的相应式数据(info.message),动态的绑定到表单元素的value属性上,然后监听 input 事件;

v-model 绑定的相应数据发生变化时,表单元素的value值也会随之变化。

<template><div><div class="message">{{ info.message }}</div><div><input v-model="info.message" type="text"></div><button @click="change">click</button></div>
</template><script>export default {data () {return {info: {}}},methods: {change () {this.info.message = 'hello world'}}}
</script>

面试题:v-for 和 v-if为什么不能一起用?

涉及到一个优先级的问题,v-for 比 v-if优先执行,如果一起使用,循环出来的每一项都会去判断一下v-if是否为true或者false,这样就会照成资源的浪费!

3.生命周期

image-20210725222206025

  • beforeCreate & created

    属于实例化阶段,在_init 方法内,DOM 被挂载时执行,两个函数都不能获取到 prop、data 中定义的值,也不能调用 methods 中定义的函数。

Vue.prototype._init = function (options?: Object) {// ...initLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, 'beforeCreate')initInjections(vm) // 在prop、data 之前解决注入initState(vm)initProvide(vm) // 解决初始化之后的prop、datacallHook(vm, 'created')// ...
}
  • beforeMount &mounted

    属于挂载阶段,在mountComponent方法内,响应数据被修改时执行,对于同步渲染的子组件而言,mounted 钩子函数的执行顺序是先子后父

export function mountComponent (vm: Component,el: ?Element,hydrating?: boolean
): Component {vm.$el = elcallHook(vm, 'beforeMount')let updateComponentif (process.env.NODE_ENV !== 'production' && config.performance && mark) {updateComponent = () => {const name = vm._nameconst id = vm._uidconst startTag = `vue-perf-start:${id}`const endTag = `vue-perf-end:${id}`mark(startTag)const vnode = vm._render()mark(endTag)measure(`vue ${name} render`, startTag, endTag)mark(startTag)// 执行vm._update 把 VNode 渲染到 真实 DOM vm._update(vnode, hydrating)mark(endTag)measure(`vue ${name} patch`, startTag, endTag)}} else {updateComponent = () => {vm._update(vm._render(), hydrating)}}// 把它设为vm._watcher 在watcher的构造函数中.// 因为观察者的初始补丁可能会调用$forceUpdate(例如:inside child . exe)// 组件的挂载钩子),依赖于vm._watcher已经定义.new Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted) {callHook(vm, 'beforeUpdate')}}}, true /* isRenderWatcher */)hydrating = false// 手动挂载实例,调用挂载在self上// 挂载在其插入的钩子中为渲染创建的子组件调用if (vm.$vnode == null) {vm._isMounted = truecallHook(vm, 'mounted')}
  • beforeUpdate & updated

    属于更新阶段,在渲染 Watcher 的 before 函数内,元素被销毁之前执行,在 callUpdatedHooks 函数中,等 vm._watcher 的回调执行完毕后,才能执行 update 函数。

export function mountComponent (vm: Component,el: ?Element,hydrating?: boolean
): Component {// ...// 把它设为vm._watcher 在watcher的构造函数中.// 因为观察者的初始补丁可能会调用$forceUpdate(例如:inside child . exe)// 组件的挂载钩子),依赖于vm。_watcher已经定义.new Watcher(vm, updateComponent, noop, {before () {if (vm._isMounted) {callHook(vm, 'beforeUpdate')}}}, true /* isRenderWatcher */)// ...
}
  • beforeDestory & destroyed (3.x中更名为 beforeUnmount & unmounted

    属于销毁阶段,在 $destroy 函数前执行,从 parent$children 中删掉自身,删除 watcher

Vue.prototype.$destroy = function () {const vm: Component = thisif (vm._isBeingDestroyed) {return}callHook(vm, 'beforeDestroy')vm._isBeingDestroyed = true// 将self从父节点移除const parent = vm.$parentif (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {remove(parent.$children, vm)}// 卸载 watchersif (vm._watcher) {vm._watcher.teardown()}let i = vm._watchers.lengthwhile (i--) {vm._watchers[i].teardown()}// 从数据ob中移除引用// frozen object 没有观察者。if (vm._data.__ob__) {vm._data.__ob__.vmCount--}// 调用最后一个钩子vm._isDestroyed = true// 在当前redered 树上调用销毁钩子vm.__patch__(vm._vnode, null)// 销毁钩子函数callHook(vm, 'destroyed')// 关闭所有实例侦听器。vm.$off()// 删除vue referenceif (vm.$el) {vm.$el.__vue__ = null}// 发布循环引用if (vm.$vnode) {vm.$vnode.parent = null}}

renderTracked & renderTriggered(3.x新增)

都是跟踪虚拟DOM 重新渲染时调用,接收 debugger event 参数;

renderTracked() : 此事件告诉你哪个操作跟踪组件,以及该操作的目标对象和键。

renderTriggered() : 此事件告诉你哪个操作触发重新渲染,以及该操作的目标对象和键。

<div id="app"><button v-on:click="addToCart">Add to cart</button><p>Cart({{ cart }})</p>
</div>
const app = Vue.vreateApp({data(){return{cart: 0}},// cart 操作*跟踪*了 组件renderTracked({ key, target, type }){console.log({ key, target, type })/*{ key: "cart", target:{cart: 0}, type: "get" }*/},// cart 操作*触发*了 重新渲染renderTriggered({ key, target, type }) {console.log({ key, target, type })},methods: {addToCart(){this.cart += 1/*{ key: "cart", target:{cart:1}, type: "set" }*/}}
})
app.mount('#app')

总结: Vue生命周期函数就是在初始化,及数据更新过程各个阶段执行不同的钩子函数;在created钩子函数中可以访问到数据,在mounted钩子函数中可以访问到DOM,在destroyed 钩子函数中可以做一些定时器销毁工作!

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

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

相关文章

modbus poll测试工具测试modbus tcp与PLC设备连接使用方法

socket默认端口是502&#xff0c;socket连上之后&#xff0c; 按照modbuspoll工具设置的读写参数 生成的RTU命令格式去组装读PLC的设备数据 modbuspoll工具配置&#xff0c;以v9.9.2中文破解版为例&#xff1a; 首先点连接菜单&#xff08;connection&#xff09;建立连接&…

C#学习(十一)——Array和Collection

一、集合 集合重要且常用 孤立的数据是没有意义的&#xff0c;集合可以作为大量数据的处理&#xff0c;可进行数据的搜索、迭代、添加、删除。 C#中&#xff0c;所有集合都必须实现ICollection接口&#xff08;数组Array除外&#xff09; 集合说明Array数组&#xff0c;固定长…

消息中间件之八股面试回答篇:三、RabbitMQ如何解决消息堆积问题(100万条消息堆积)+RabbitMQ高可用性和强一致性机制+回答模板

RabbitMQ中的消息堆积问题 当生产者发送消息的速度超过了消费者处理消息的速度&#xff0c;就会导致队列中的消息堆积&#xff0c;直到队列存储消息达到上限。之后发送的消息就会成为死信&#xff0c;可能会被丢弃&#xff0c;这就是消息堆积问题。 解决消息堆积有三种种思路…

【Java Kubernates】Java调用kubernates提交Yaml到SparkOperator

背景 目前查询框架使用的是trino&#xff0c;但是trino也有其局限性&#xff0c;需要准备一个备用的查询框架。考虑使用spark&#xff0c;spark operator也已经部署到k8s&#xff0c;现在需要定向提交spark sql到k8s的sparkoperator上&#xff0c;使用k8s资源执行sql。 对比 …

LeetCode 40.组合总和 II

组合总和 II 给定一个候选人编号的集合 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意&#xff1a;解集不能包含重复的组合。 方法一、回溯 由于题目要求解集…

C语言第十一弹---函数(下)

​ ✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 函数 1、嵌套调用和链式访问 1.1、嵌套调用 1.2、链式访问 2、函数的声明和定义 2.1、单个文件 2.2、多个文件 2.3、static 和 extern 2.3.1、static…

机器学习的数据库积累........

https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/tf1_detection_zoo.md ​​​​​​​ 另一个database:&#xff08;网址:Object Detection Made Easy with TensorFlow Hub: Tutorial&#xff09; Object Detection Made Easy with Ten…

菱形打印和十进制ip转二进制

1.菱形打印 用for循环 #!/bin/bashread -p "请输入菱形的大小:" num #打印向上的等腰三角形 for ((i=1;i<=num;i++)) dofor ((j=num-1;j>=i;j--))doecho -n " " #打印的是前面的空格donefor ((k=1;k<=2*i-1;k++))doecho -n "*" #打印…

蓝桥杯——每日一练(简单题)

题目 问题描述   123321是一个非常特殊的数&#xff0c;它从左边读和从右边读是一样的。   输入一个正整数n&#xff0c; 编程求所有这样的五位和六位十进制数&#xff0c;满足各位数字之和等于n 。 输入格式   输入一行&#xff0c;包含一个正整数n。 输出格式   按从…

基于vue实现待办清单案例

一、需求 新增内容&#xff1b; 删除内容&#xff1b; 统计操作&#xff1b; 清空数据。 示例图&#xff1a; 二、代码演示 1、基础准备 index.css代码 html, body {margin: 0;padding: 0; } body {background: #fff ; } button {margin: 0;padding: 0;border: 0;backgr…

C++ 隐式转换构造函数和explicit 关键字学习

据说在内核代码中,多个地方使用了explicit 关键字;下面看一下; 在 C++ 中,隐式转换构造函数指的是当我们将一种类型的值赋给该类对象时,编译器会自动调用相应的构造函数进行类型转换。这样可以使得不同类型之间能够互相赋值或者传参。 具体来说,当一个类有多个构造函数…

数据结构(1)--> 顺序表

定义&#xff1a; 顺序表存储定义&#xff1a; 把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构&#xff0c;顺序表功能的实现借助于数组&#xff0c;通过对数组进行封装&#xff0c;从而实现增删查改的功能&#xff0c;严格意义上来说&#xff08;数组无法实现…

vue3+echarts绘制某省区县地图

vue3echarts绘制某省区县地图 工作中经常需要画各种各样的图&#xff0c;echarts是使用最多的工具&#xff0c;接近春节&#xff0c;想把之前画的echarts图做一个整合&#xff0c;方便同事和自己随时使用&#xff0c;因此用vue3专门写了个web项目&#xff0c;考虑之后不断完善…

STM正点mini-新建工程模板,GPIO及寄存器(介绍)

一.新建工程模板(基于固件库) 1.1库函数与寄存器的区别 这里的启动文件都是根据容量来进行区分的 对MDK而言即使include了&#xff0c;也不知道在哪里找头文件 STM32F10X_HD,USE_STDPERIPH_DRIVER 二.新建工程模板(基于寄存器) 上面的大部分配置与固件库的一样 具体可以看手…

第5章 (python深度学习——波斯美女)

第5章 深度学习用于计算机视觉 本章包括以下内容&#xff1a; 理解卷积神经网络&#xff08;convnet&#xff09; 使用数据增强来降低过拟合 使用预训练的卷积神经网络进行特征提取 微调预训练的卷积神经网络 将卷积神经网络学到的内容及其如何做出分类决策可视化 本章将…

【Linux】开始使用 vim 吧!!!

Linux 1 what is vim &#xff1f;2 vim基本概念3 vim的基本操作 &#xff01;3.1 vim的快捷方式3.1.1 复制与粘贴3.1.2 撤销与剪切3.1.3 字符操作 3.2 vim的光标操作3.3 vim的文件操作 总结Thanks♪(&#xff65;ω&#xff65;)&#xff89;感谢阅读下一篇文章见&#xff01;…

成熟的内外网数据交换方案,如何实现跨网传输?

网络迅速发展&#xff0c;我们可以从网络上查找到各式各样的信息&#xff0c;但是同时网络安全问题也随之严重。近几年&#xff0c;各种有关网络安全的新闻不断被报道&#xff0c;数据泄露给很多企业带来了严重打击&#xff0c;不仅是经济损失&#xff0c;严重者还会对企业的声…

SharedPreferences卡顿分析

SP的使用及存在的问题 SharedPreferences(以下简称SP)是Android本地存储的一种方式&#xff0c;是以key-value的形式存储在/data/data/项目包名/shared_prefs/sp_name.xml里&#xff0c;SP的使用示例及源码解析参见&#xff1a;Android本地存储之SharedPreferences源码解析。以…

STM32 PWM驱动设计

单片机学习&#xff01; 目录 文章目录 前言 一、PWM驱动配置步骤 二、代码示例及注意事项 2.1 RCC开启时钟 2.2 配置时基单元 2.3 配置输出比较单元 2.4 配置GPIO 2.5 运行控制 三、PWM周期和占空比计算 总结 前言 PWM本质是利用面积等效原理来改变波形的有效值。 一、PWM驱动…

git安装步骤

安装环境&#xff1a;Windows10 64bit 下载 Git网址 &#xff1a;Git - Downloading Package 版本&#xff1a;Git-2.21.0-64-bit 第一步&#xff1a;双击下载后的Git-2.21.0-64-bit.exe&#xff0c;开始安装 安装开始 第二步&#xff1a;选择安装路径&#xff0c;点击[next]…