Vue data 中随意更改一个属性,视图都会被更新吗?
以下内容来自公众号逆锋起笔,关注每日干货及时送达
作者:Rudy24
链接:https://juejin.cn/post/7040733315791323143
面试官:看过 Vue 的源码没?
候选者:看过。
面试官:那你说下 Vue data 中随意更改一个属性,视图都会被更新吗?
候选者:不会。
面试官:why?
候选者:如果该属性没有被用到 template 中,就没有必要去更新视图,频繁这样性能不好。
面试官:那 Vue 中是如何去实现该方案的?
候选者:在实例初始化过程中,利用
Object.defineProperty
对 data 中的属性进行数据监听,如果在 template 中被使用到的属性,就被 Dep 类收集起来,等到属性被更改时会调用notify
更新视图。面试官:那你怎么知道那些属性是在 template 被用到的呢?
候选者:WTF。。。这个倒不是很清楚,您能解释下吗?
面试官:OK,那我就简单解释下:
先写个简单的 demo,其中 data 中有 4 个属性a,b,c,d
,在模板中被利用到的属性只有a,b
。看看是不是只有a,b
才会调用Dep
收集起来呢?
new Vue({el: '#app',data() {return {a: 1,b: 2,c: 3,d: 4,};},created() {console.log(this.b);this.b = 'aaa';},template: '<div>Hello World{{a}}{{b}}</div>',
});
复制代码
在Vue
instance/state.js
里面,会利用proxy
把每个属性都 代理一遍
const keys = Object.keys(data)const props = vm.$options.propsconst methods = vm.$options.methodslet i = keys.lengthwhile (i--) {const key = keys[i]if (props && hasOwn(props, key)) {process.env.NODE_ENV !== 'production' && warn(`The data property "${key}" is already declared as a prop. ` +`Use prop default value instead.`,vm)} else if (!isReserved(key)) {// 代理对象的属性proxy(vm, `_data`, key)}}// observe dataobserve(data, true /* asRootData */)
复制代码
利用
defineReactive
对data中的每个属性进行劫持
observe(data, true /* asRootData */);// observe
const keys = Object.keys(obj);
for (let i = 0; i < keys.length; i++) {defineReactive(obj, keys[i]);
}// defineReactive
Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter() {const value = getter ? getter.call(obj) : val;// 重点在这里,后续如果在模板中使用到的属性,都会被执行reactiveGetter函数// 被Dep类 收集起来if (Dep.target) {console.log(`${key} 属性 被Dep类收集了`)dep.depend();if (childOb) {childOb.dep.depend();if (Array.isArray(value)) {dependArray(value);}}}return value;},set: function reactiveSetter(newVal) {const value = getter ? getter.call(obj) : val;/* eslint-disable no-self-compare */if (newVal === value || (newVal !== newVal && value !== value)) {return;}if (setter) {// 这里是处理computed set 函数setter.call(obj, newVal);} else {val = newVal;}childOb = !shallow && observe(newVal);// 如果我们在更改属性时,就会调用notify 异步更新视图dep.notify();},
});
复制代码
执行
$mount
进行视图挂载
if (vm.$options.el) {vm.$mount(vm.$options.el);
}
复制代码
$mount
是调用 Vue 原型上的方法, 重点是最后一句mount.call(this, el, hydrating)
Vue.prototype.$mount = function (el?: string | Element,hydrating?: boolean
): Component {el = el && query(el);const options = this.$options;// resolve template/el and convert to render function/*** 查看render 函数是否存在?如果不存在就解析template模板* Vue渲染页面时,有两个方式 1. template,2. render,最终所有的模板类的都需要使用render去渲染*/if (!options.render) {let template = options.template;if (template) {if (typeof template === 'string') {if (template.charAt(0) === '#') {template = idToTemplate(template);/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && !template) {warn(`Template element not found or is empty: ${options.template}`,this);}}} else if (template.nodeType) {template = template.innerHTML;} else {if (process.env.NODE_ENV !== 'production') {warn('invalid template option:' + template, this);}return this;}} else if (el) {// 如果模板不存在,就创建一个默认的html模板template = getOuterHTML(el);}}// 重写了Vue.prototype.$mount ,最终调用缓存的mount方法完成对$mount的挂载return mount.call(this, el, hydrating);
};
复制代码
这里
mount
调用了mountComponent(this, el, hydrating)
方法,而mountComponent
是执行了_render
函数,最终_render
是调用render
生成一个vnode
。
const { render, _parentVnode } = vm.$options;
vnode = render.call(vm._renderProxy, vm.$createElement);
复制代码
最后一张图可以看到是render
函数在渲染我们demo里面的template
模板,最终只有a, b
两个属性才会被Dep
类收集起来。微信搜索readdot,关注后回复视频教程获取23种精品资料
如果文中有错误的地方,麻烦各位指出,我会持续改进的。谢谢, 需要调试源码的,这里点击这里,按照 readme操作即可。
逆锋起笔
专注于程序员圈子,你不但可以学习到java
、python
等主流技术干货,还可以第一时间获悉最新技术动态
、内测资格
、BAT大佬的经验
、精品视频教程
、副业赚钱
经验,微信搜索readdot
关注!
Vue3 相比于 Vue2 有哪些 “与众不同”?
Vue 开发最佳指南,你都需要学点啥?
记一次 Vue3.0 技术分享会
Vue 实战中的一些小魔法
一名 Vue 程序员总结的 React 基础
点一下,代码无 Bug
Vue data 中随意更改一个属性,视图都会被更新吗?相关推荐
- android addview指定位置,Android开发中,请问当在一个视图中addView另一个布局视图时为什么报错?...
Android开发中,我在一个视图中addView另一个布局视图(该视图通过inflate加载获得,其中root为null即没有附加parent视图),为什么还是会报错误: The specified ...
- 有属性的自定义注解,如何获取到post请求中RequestBody中对象的一个属性值?
1,写两个自定义注解,一个作用于方法的,一个作用于字段的 作用于方法的自定义注解代码: package com.youku.nintendo.annotation;import enums.Permi ...
- 微信小程序,直接给data中的对象添加属性
data:{ testData:{} }, onLoad(){ const testData = this.data.testData;this.setData({['testData.li']:'1 ...
- 在SAP系统中,更改一个公司代码(Company Code)的会计科目表(Chart of Accounts)
通常,我们在SAP系统中会通过复制一个已有的公司代码来创建一个新的公司代码.这种情况下,如果我们想改变"新创建出的company code"的会计科目表,应该如何做呢? 通常需要如 ...
- python中如何对一个属性或方法进行封装_python学习第20天
一.面向对象oop - 封装 1.类中封装: 成员属性和成员方法 2.封装等级 公有:公有成员既能够在类外调用,也可以在类调用 私有:私有成员不能够在类外调用,可以在类内调用 (前面加上双下划线表示) ...
- vue data 中的 return 用法
文章目录 一.vue 里面的data return 是什么? 二.如何使用 1.vue 双向绑定 v-model 2.带有 ":"的属性 比如:class.:id等等 3. 标签使 ...
- java properties $,如何引用java.util.Properties中的另一个属性?
由于eproperties是有点不维护和commonsconfiguration依赖于日志logging(具有讽刺意味的是你不能用它来configuration日志logging)我使用这个代码片段, ...
- 遍历一个类中的每一个属性、方法、公共字段
//获取对象类型 Type t = obj.GetType(); //获取类的属性 PropertyInfo[] propertys = t.GetPr ...
- vue监听对象某一个属性
watch: {uploadObj: {//监听对象deep: true,handler: function(value) {if (!value.receiver && !value ...
最新文章
- XGBOOST带试验源码
- Ansible9:条件语句【转】
- sudo: /etc/sudoers is world writable 错误解决方案
- ChannelFactory创建和销毁昂贵
- jvm在windows和linux,理解JVM如何使用Windows和Linux上的本机内存
- leetcode 421. Maximum XOR of Two Numbers in an Array | 421. 数组中两个数的最大异或值(位运算,Trie前缀树)
- selenium java 断言_Java+Selenium+Testng自动化测试学习(三)— 断言
- python入门需要有什么基础?
- Windows server 2008 R2实现多用户远程连接
- SpringMVC入门笔记
- python数据类型—字符串
- php自己编译扩展,Linux编译PHP添加扩展库的方法
- 《PRML》学习笔记2.2——多项式分布和狄利克雷分布
- win10桌面背景为什么突然变黑了 win10桌面背景不显示解决方法
- 使用空驱动消除设备管理器里面的未知设备
- Messari:21年第二季度Web3及NFT报告
- Jmeter dubbo插件测试dubbo接口
- 20180402-A · US Tuition Costs · ggplot2, 折线图 · R 语言数据可视化 案例 源码
- 等边三角形的积木编程
- 【渝粤教育】电大中专新媒体营销实务 作业 题库
热门文章
- MATLAB的交互式界面 简易设计
- 如何用随机森林算法,在深海养肥一群鱼
- 激光雷达和毫米波雷达工作原理对比
- C++——素数(质数)专题训练
- 汇编实现文件内容的base64编码
- 当前对计算机专业人才的要求,关于计算机专业人才需求的分析
- python列表推导式去除m3u8中的广告视频地址下载视频
- 2019多校第三场 HDU6608	Fansblog(威尔逊定理,逆元,质数间隔)
- 北京大学肖臻老师《区块链技术与应用》ETH笔记 - 8.0 ETH挖矿难度的调整
- TIA博途V16专业版与博途V15.1专业版或其他版本能否安装在同一台PC中?