【Vue 3.0 新特性(四)】Vue 3.0 响应式系统原理
文章前言
笔记来源:拉勾教育 大前端高薪训练营
阅读建议:内容较多,建议通过左侧导航栏进行阅读
Vue 3.0 响应式系统原理
基础回顾
Vue.js 响应式回顾
- Proxy 对象实现属性监听
- 多层属性嵌套,在访问属性过程中处理下一级属性
- 默认监听动态添加的属性
- 默认监听属性的删除操作
- 默认监听数组索引和 length 属性
- 可以作为单独的模块使用
Proxy 对象回顾
'use strict'
// 问题1: set 和 deleteProperty 中需要返回布尔类型的值
// 在严格模式下,如果返回 false 的话会出现 Type Error 的异常
const target = {foo: 'xxx',bar: 'yyy'
}
// Reflect.getPrototypeOf()
// Object.getPrototypeOf()
/*** @param { Object } target 目标对象* @param { Object } {} 处理器 / 监听器,处理函数*/
const proxy = new Proxy(target, {get (target, key, receiver) {// return target[key]return Reflect.get(target, key, receiver)},set (target, key, value, receiver) {// target[key] = valuereturn Reflect.set(target, key, value, receiver)},deleteProperty (target, key) {// delete target[key]return Reflect.deleteProperty(target, key)}
})proxy.foo = 'zzz'
// delete proxy.foo
// 问题2:Proxy 和 Reflect 中使用的 receiver// Proxy 中 receiver:Proxy 或者继承 Proxy 的对象
// Reflect 中 receiver:如果 target 对象中设置了 getter,getter 中的 this 指向 receiverconst obj = {get foo() {console.log(this)return this.bar}
}const proxy = new Proxy(obj, {get (target, key, receiver) {if (key === 'bar') { return 'value - bar' }return Reflect.get(target, key, receiver)}
})
console.log(proxy.foo)
reactive
- reactive 返回的对象,重新赋值丢失响应式
- reactive 返回的对象不可以解构
基础实现
接收一个参数,判断参数是否是对象
创建拦截器对象
handler
,设置get / set / deleteProperty
返回
Proxy
对象// 判断 target 是否是对象 const isObject = val => val !== null && typeof val === 'object' // 当返回的数据还是对象时,需要递归调用,收集依赖 const convert = target => isObject(target) ? reactive(target) : target// 判断某个对象本身是否有指定的属性 const hasOwnProperty = Object.prototype.hasOwnProperty const hasOwn = (target, key) = hasOwnProperty(target, key)export function reactive (target) {if (!isObject(target)) return targetconst handler = {get (target, key, receiver) {// 收集依赖track(target, key)const result = Reflect.get(target, key, receiver)return convert(result)},set (target, key, value, receiver) {const oldValue = Reflect.get(target, key, receiver)let result = trueif (oldValue !== value) {result = Reflect.set(target, key, value, receiver)// 触发更新trigger(target, key)}return result},deleteProperty (target, key) {const hasKey = hasOwn(target, key)const result = Reflect.defineProperty(target, key)if (hasKey && result) {// 触发更新trigger(target, key)}return result}}return new Proxy(target, handler) }
收集依赖
功能结构,如图所示:
代码实现,如下所示:
// 收集依赖 let activeEffect = null export function effect (callback) {activeEffect = callbackcallback() // 访问响应式对象属性,去收集依赖activeEffect = null }let targetMap = new WeakMap() export function track (target, key) {if (!activeEffect) returnlet depsMap = targetMap.get(target)if (!depsMap) {targetMap.set(target, (depsMap = new Map()))}let dep = depsMap.get(key)if (!dep) {depsMap.set(key, (dep = new Set()))}dep.add(activeEffect) }
触发更新
具体代码实现,如下所示:
// 触发更新 export function trigger (target, key) {const depsMap = targetMap.get(target)if (!depsMap) returnconst dep = depsMap.get(key)if (dep) {dep.forEach(effect => {effect()})} }
ref
ref 可以把基本数据类型数据,转成响应式对象
ref 返回的对象,重新赋值成对象也是响应式的
export function ref(raw) {// 判断 raw 是否是 ref 创建的对象,如果是的话,直接返回if (isObject(raw) && raw.__v_isRef) returnlet value = convert(raw)const r = {__v_isRef: true,get value() {track(r, 'value')return value},set value(newValue) {if (newValue !== value) {raw = newValuevalue = convert(raw)trigger(r, 'value')}}}return r }
toRefs
接收一个 reactive 返回的响应式对象,即一个 Proxy 对象
把传入对象的属性转化为类似于 ref 返回的对象
把转换后的属性,挂载到一个新的对象上,进行返回
// 接收一个 reactive 返回的响应式对象,即一个 Proxy 对象 export function toRefs (proxy) {const ret = proxy instanceof Array ? new Array(proxy.length) : {}// 把转换后的属性,挂载到一个新的对象上,进行返回for (const key in proxy) {ret[key] = toProxyRef(proxy, key)}return ret } // 把传入对象的属性转化为类似于 ref 返回的对象 function toProxyRef (proxy, key) {const r = {__v_isRef: true,get value () {return proxy[key]},set value (newValue) {proxy[key] = newValue}}return r }
computed
监听内部响应式数据的变化
export function computed(getter) {const result = ref()effect(() => {result.value = getter()})return result }
【Vue 3.0 新特性(四)】Vue 3.0 响应式系统原理相关推荐
- input change获取改变之前的值和改变之后的值_使用Vue3.0新特性造轮子 WidgetUI3.0 (Input输入框组件)
我们先看看组件效果图: 基本用法 type属性(type="password") 占位符(placeholder="请输入") 带清除按钮(clear) 输入限 ...
- accept 返回0_使用Vue3.0新特性造轮子 WidgetUI3.0 (Upload上传文件组件)
我们先看看组件效果: 基本使用 可选参数( icon='icon-service') props属性: title(类型 String) 组件显示的文本,默认"上传'. icon(类型 St ...
- Servlet 3.0 新特性概述
Servlet 3.0 新特性概述 Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布.该版本在前一版本(Servlet 2.5)的基础上提供了若 ...
- Servlet 3.0 新特性详解
https://www.ibm.com/developerworks/cn/java/j-lo-servlet30/ Servlet 3.0 新特性概述 Servlet 3.0 作为 Java EE ...
- 安卓6.0、7.0、8.0新特性总结异同
android6.0 参考一:简书Android 6.0 新特性详解 参考二:关于Android6.0以上系统的权限问题 参考三:值得你关注的Android6.0上的重要变化(一) 参考四:值得你关注 ...
- JDK5.0新特性系列---目录
JDK5.0新特性系列---目录 JDK5.0新特性系列---1.自动装箱和拆箱 JDK5.0新特性系列---2.新的for循环 JDK5.0新特性系列---3.枚举类型 JDK5.0新特性系列--- ...
- 背水一战 Windows 10 (1) - C# 6.0 新特性
背水一战 Windows 10 (1) - C# 6.0 新特性 原文:背水一战 Windows 10 (1) - C# 6.0 新特性 [源码下载] 背水一战 Windows 10 (1) - C# ...
- 背水一战 Windows 10 (43) - C# 7.0 新特性
背水一战 Windows 10 (43) - C# 7.0 新特性 原文: 背水一战 Windows 10 (43) - C# 7.0 新特性 [源码下载] 背水一战 Windows 10 (43) ...
- 老子学不动系列:Vue 3.0 新特性预览
尤大昨天在 Vue Toronto 的主题演讲中预览了 Vue 3 .通过利用现代浏览器支持的新功能,Vue 3 将成为我们已经了解和喜爱的Vue.js 的改进版本. 我们期待的 Vue 3 将会是: ...
最新文章
- ubuntu package XXX needs to be reinstalled,but I can't find an archive 问题修复
- Python 输入输出
- 10-异步爬虫(线程池/asyncio协程)实战案例
- mysql 连接 指定字符集_关于Mysql连接池配置指定字符集的问题
- java实现代理服务器,接收客户端连接,发送到对应服务器
- 老式计算机如何设置u盘启动,技嘉主板老式bios设置u盘启动教程
- php 泛型编程,泛型是什么,C++泛型编程又是什么?
- 微信支付服务商平台(商户平台)扫码登录后提示“登录超时,请重新登录”时该怎么处理?
- SpaceEye :12种地球实时卫星照片壁纸
- 省选LN站2023游记Day1
- 如何对待每逢佳节被逼婚
- 怀念—伤心者,不痛不痒,冷暖自知
- 编译安装mysql5.5
- java 一元 二元 三元_一元到三元关系 二元
- 澳大利亚兽医伏特加酒当点滴救活给中毒小狗
- Pandas数据可视化的备忘录
- 什么?你还没妹子?教你如何借助Python俘获女孩子芳心
- Matalb更换YaHei Consolas Hybrid字体
- 邪教日记之神兵篇: 一
- html5富文本编辑器图片,漂亮的富文本编辑器WYSIWYG