精简Vue3源码解析,实现一个mini版【Vue3】

在看这篇文章之前希望大家还是有一定的基础,能够了解Vue2的一些基础原理,了解Proxy代码的基础应用以及WeakMap,Map,Set这些数据结构的特性。如果对这些还不了解的同学建议先去补一下基础知识。

如果你对vue3还不了解建议先去学习下vue3。

vue3基础特性

vue3+Ts实战

声明: 本文中采用的方法名均为源码中的方法名,很多代码结构按照源码的结构来写的,目的就是在于希望能够对想看源码的同学做一些引导。

如果代码中有些地方你不能一下子想明白的,先尝试去接受它,然后回过头来再去理解它。

重中之重:对于本文的学习方式上希望大家一定要更着去手写代码,多做一些思考,看完之后我相信你一定会有所收获。

如果有什么不对的地方也欢迎大家留言指正。

响应式

我们都知道vue2中是通过defineProperty实现对数据的拦截监听,而vue3中采用的Proxy,相较于defineProperty,即能监听数组,不需要进行嵌套,不用遍历每个属性,针对整个对象更加轻便。

vue3通过reactive创建一个响应式对象,当对象被修改的时候,视图也会随着更新,对应的副作用函数也会执行(这个我们后面实现watchEffect的时候再分析)。这其中主要有两个过程:

  • 对数据进行监听并收集依赖
  • 更新视图(后话)

reactive内部就是通过Proxy实现对数据的拦截监听。

// v3.js

// reactive 的实现
function reactive(target){
    return createReactiveObject(
        target,
        mutableHandlers
    );
}

/**
 * 真正创建响应式对象的函数
 * @param {*} target 对象
 * @param {*} handler 处理程序
 */
function createReactiveObject(target,handler){
    const proxy = new Proxy(target,handler);
    return proxy;
}
复制代码

Proxy对数据的监听主要在handler中进行处理, handler是一个定义一个或多个陷阱的对象。接着我们实现一下mutableHandlers对象

// v3.js

const get = createGetter();
function createGetter(){
    return function get(target,key,receiver){
        const res = Reflect.get(target, key, receiver);
        console.log('get执行了',key);
        return res;
    }
}

const set = createSetter();
function createSetter(){
    return function set(target,key,value,receiver){
        const res = Reflect.set(target,key,value,receiver);
        console.log('set执行了',key);
        return res;
    }
}

// proxy的处理程序,是一个定义一个或多个陷阱的对象
// 只处理简单的 get 和 set
const mutableHandlers = {
    get,
    set
}

// reactive 的实现
function reactive(target){
  return createReactiveObject(
    target,
    mutableHandlers
  );
}

/**
 * 真正创建响应式对象的函数
 * @param {*} target 对象
 * @param {*} handler 处理程序
 */
function createReactiveObject(target,handler){
  const proxy = new Proxy(target,handler);
  return proxy;
}
复制代码

这样我们就实现了一个简单的reactvie,能够对数据进行监听了。可以通过以下代码测试一下:

// v3.js

const testObj = reactive({ count:10 }})
testObj.count
testObj.count = 20

// 通过node v3.js执行当前代码
// get执行了 count
// set执行了 count
复制代码

这只是实现了对简单对象的监听,如果对象复杂一点,就会存在问题,例如:

// v3.js

const testObj = reactive({ count:10, info: { name:'lucas' }})
testObj.info.name
testObj.info.name = 'viky'

// 执行结果如下
// get执行了 count
// set执行了 count
复制代码

这样监听就失效了,没有监听到name属性,优化一下get方法,如果当值为对象的时候,我们应该递归监听:

// v3.js

const isObject = (target)=>{ return target !== null && typeof target === 'object'}
function createGetter(){
    return function get(target,key,receiver){
        const res = Reflect.get(target, key, receiver);
        console.log('get执行了',key);
        if(isObject(res)){
            return reactive(res);
        }
        return res;
    }
}
复制代码

到这里我们的reactive已经实现了对数据的监听。

订阅

接下来我们开始收集依赖,依旧是在get中进行处理,通过track函数进行依赖收集,在这之前先大致介绍一下vue3中用于存储依赖的数据结构。

20210326151449 (1)_gaitubao_375x265.jpg

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享