一、响应性原理
数据模型 是被代理的 JavaScript 对象。而当你修改它们时,视图会进行更新。这让状态管理非常简单直观。
理解其工作原理同样重要,这样可以避开一些常见的问题。
1 什么是响应性?
响应性是 一种允许我们以声明式的方式去适应变化的一种编程范例。如excell。
js如何实现响应性
- 检测其中某一个值是否发生变化
- 用跟踪 (track) 函数修改值
- 用触发 (trigger) 函数更新为最新的值
2 Vue如何追踪变化?
底层原理:
当把一个普通的 JavaScript 对象作为 data 选项传给应用或组件实例的时候,Vue 会使用带有 getter 和 setter 的处理程序遍历其所有 property 并将其转换为 Proxy
这是 ES6 仅有的特性,但是我们在 Vue 3 版本也使用了 Object.defineProperty 来支持 IE 浏览器。
两者具有相同的 Surface API,但是 Proxy 版本更精简,同时提升了性能。
Proxy相关:
Proxy 是一个 包含另一个对象或函数 并允许你对其进行拦截 的对象。
用法:new Proxy ( tatget,handler )
a. 我们把对象包装在 Proxy 里的同时,可以对其进行拦截。这种拦截被称为陷阱。
b. Proxy 还提供了另一个特性。我们不必像这样返回值:target[prop],而是可以进一步使用一个名为 Reflect 的方法,它允许我们正确地执行 this 绑定。
详见: https://vue3js.cn/docs/zh/guide/reactivity.html
总结:
将对象作为数据传递给组件实例时,Vue 会将其转换为 Proxy。
这个 Proxy 使 Vue 能够在 property 被访问或修改时 执行依赖项跟踪 和 更改通知。每个 property 都被视为一个依赖项。
首次渲染后,组件将跟踪一组依赖列表——即在渲染过程中被访问的 property。
反过来,组件就成为了其每个 property 的订阅者。当 Proxy 拦截到 set 操作时,该 property 将通知其所有订阅的组件重新渲染。
响应性基础
1 reactive 声明响应式状态(为 JavaScript 对象创建响应式状态)
import { reactive } from 'vue'
// 响应式状态
const state = reactive({
count: 0
})
2ref 创建独立的响应式值(比如一个字符串)
ref 会返回一个可变的响应式对象,该对象作为它的内部值——一个响应式的引用,这就是名称的来源。
此对象只包含一个名为 value 的 property 。
import { ref } from 'vue'
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
⚠️ ref展开:当 ref 作为渲染上下文 (从 setup() 中返回的对象) 上的 property 返回 并可以在模板中被访问时,它将自动展开为内部值。不需要在模板中追加 .value

a. 当 ref 作为响应式对象的 property 被访问或更改时,为使其行为类似于普通 property,它会自动展开内部值。
b. 如果将新的 ref 赋值给 现有 ref 的 property,新的 ref 将会替换旧的 ref.
c. ref 展开仅发生在被响应式 Object 嵌套的时候。当从 Array 或原生集合类型如 Map访问 ref 时,不会进行展开.
3toRefs :响应式状态 解构,toRefs 可 保留 与源对象的响应式关联
import { reactive, toRefs } from 'vue'
const book = reactive({
author: 'Vue Team',
year: '2020',
title: 'Vue 3 Guide',
description: 'You are reading this book right now ;)',
price: 'free'
})
let { author, title } = toRefs(book)
title.value = 'Vue 3 Detailed Guide' // 我们需要使用 .value 作为标题,现在是 ref
console.log(book.title) // 'Vue 3 Detailed Guide'
4readonly :使用readonly 防止更改响应式对象 (可以基于原始对象 创建一个只读的 Proxy 对象)
import { reactive, readonly } from 'vue'
const original = reactive({ count: 0 })
const copy = readonly(original)
// 在copy上转换original 会触发侦听器依赖
original.count++
copy.count++ // 转换copy 将导失败并导致警告 "Set operation on key 'count' failed: target is readonly."
响应式计算和侦听
1computed : 计算值(当需要依赖其他状态时,可用computed来计算得出。它接受 getter 函数并为 getter 返回的值返回一个不可变的响应式 ref 对象。)
const count = ref(1) const plusOne = computed(() => count.value++) console.log(plusOne.value) // 2 plusOne.value++ // error
const count = ref(1)
const plusOne = computed({ //或者,它可以使用一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusOne.value = 1
console.log(count.value) // 0
2watchEffect: 副作用(根据响应式状态 自动应用 和 重新应用 副作用。它立即执行 传入的 一个函数,同时响应式追踪依赖,并在该依赖变更时,重新运行该函数。)
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> logs 0
setTimeout(() => {
count.value++
// -> logs 1
}, 100)
stop: 停止侦听(当 watchEffect 在组件的 setup() 函数或生命周期钩子被调用时,侦听器会被链接到该组件的生命周期,并在组件卸载时自动停止)
const stop = watchEffect(() => {
/* ... */
})
// later
stop()
onInvalidate: 清除副作用(侦听副作用传入的函数 可以接收一个 onInvalidate 函数作入参,用来注册清理失效时的回调)
3watch: 等同于组件侦听器 (侦听特定的数据源,并在回调函数中执行副作用。默认情况下,它也是惰性的,即只有当被侦听的源发生变化时才执行回调)
与 watchEffect 比较,watch 允许我们:
- 懒执行 副作用;
- 更具体地说明什么状态应该触发侦听器重新运行;
- 访问 侦听状态变化前后的值

浙公网安备 33010602011771号