先看个示例:
- const {effect, reactive} = require('@vue/reactivity')
-
- let dummy
- const counter = reactive({ num1: 1, num2: 2 })
- effect(() => {
- dummy = counter.num1 + counter.num2
- console.log(dummy)// 每次counter.num1修改都会打印日志
- })
- setInterval(()=>{
- counter.num1++
- },1000)
我们先使用 reactive 把普通的 JavaScript 对象包裹成响应式数据,然后在 effect 中获取 counter.num1 和 counter.num2 的时候,就会触发 counter 的 get 拦截函数;get 函数,会把当前的 effect 函数注册到一个全局的依赖地图中去。这样 counter.num1 在修改的时候,就会触发 set 拦截函数,去依赖地图中找到注册的 effect 函数,然后执行。
具体是怎么实现的呢?我们从第一步把数据包裹成响应式对象开始。先看 reactive 的实现。
Vue3 中,reactive 是通过 ES6 中的 Proxy 特性实现的属性拦截,所以,在 reactive 函数中我们直接返回 newProxy 即可:
- export function reactive(target) {
- if (typeof target!=='object') {
- console.warn(`reactive ${target} 必须是一个对象`);
- return target
- }
-
- return new Proxy(target, mutableHandlers);
- }
这里我们只拦截 get 和 set 操作。
- const get = createGetter();
- const set = createSetter();
-
- function createGetter(shallow = false) {
- return function get(target, key, receiver) {
- const res = Reflect.get(target, key, receiver)
- track(target, "get", key)
- if (isObject(res)) {
- // 值也是对象的话,需要嵌套调用reactive
- // res就是target[key]
- // 浅层代理,不需要嵌套
- return shallow ? res : reactive(res)
- }
- return res
- }
- }
-
- function createSetter() {
- return function set(target, key, value, receiver) {
- const result = Reflect.set(target, key, value, receiver)
- // 在触发 set 的时候进行触发依赖
- trigger(target, "set", key)
- return result
- }
- }
- export const mutableHandles = {
- get,
- set,
- };
转载:极客时间-Vue3课程