重写数据劫持

153 阅读2分钟

数据代理

响应式依赖于vue-next下面的reactivity包,这个包是独立于其他的包

-src文件夹

​ -vue3文件夹

​ -index.js(同级)

​ -index.html

​ -shared文件夹

​ -utils.js

​ -reactivity文件夹

​ -index.js

​ -reactive.js

​ -mutableHandle.js

-webpack.config.js

-package.json

index.js(同级)

import { reactive } from "./vue3/reactive"
// reactive =>es6 的proxy代理API
const state = reactive({
    name:'小笨蛋',
    age:21,
    info:{
        job:'student',
        students:[
            {
                id:1,
                name:'小'
            },
            {
                id:2,
                name:'笨'
            }
        ]
    },
    hobby:['piano','film']
});
state.name;//响应式获取:小笨蛋
state.name = '元元儿'///响应式设置:name=元元儿

//因为只有第一层代理,所以取到里面的东西不行,比如:
//state.info.job

index.js

//导入reactive
import {reactive} from "./reactive";

export {
    reactive
}

reactive.js

//导入shared下面的工具函数
import { isObject } from "../shared/utils"
import { mutableHandle } from "./mutableHandle"

/*
    希望有一个函数去处理响应式的代理的转换
*/

function reactive(target) {
    //target  是一个对象
    /*传入两个参数
        target 
        mutableHandle 
    */
    return createReactiveObject(target, mutableHandle);//执行的结果是observer 是一个被代理后的对象
    //mutableHandle里面有很多东西,创建一个文件单独管理
}

function createReactiveObject(target, baseHandler) {

    if (!isObject(target)) {
        return target
    }
    const observer = new Proxy(target, baseHandler);//此处还需要关注target到底是不是一个对象,如果不是对象不需要代理
    //所以在vue3下面创建一个shared文件夹 里面的utils.js文件判断
    return observer;
}

//导出reactive
export {
    reactive
}

utils.js

function isObject(value) {
    return typeof value === 'object' && value !== null;
}

//target对象中到底存不存在key值,如果没有就是新增的
function hasOwnProperty(target, key) {
    return Object.prototype.hasOwnProperty.call(target, key);
}

function isEqual(newValue, oldValue) {
    return newValue === oldValue;
}

export {
    isObject,
    hasOwnProperty,
    isEqual
}

mutableHandle.js

//handler下面有很多方法,为了将handler的方法能够单独的去完成
import { isObject } from "../shared/utils"
import { reactive } from "./reactive";
import {hasOwnProperty,isEqual} from "../shared/utils"

//可以去创建一个createGetter等方法
const get = createGetter();
const set = createSetter();


//刚开始说了get和set都含有几个参数,所以返回的时候也需要包含这些参数
function createGetter() {
    return function get(target, key, receiver) {
        const res = Reflect.get(target, key, receiver);
        console.log('响应式获取' + target[key]);

        //因为需要获取到对象里面的对象的属性

        if (isObject(res)) {
            return reactive(res);
        } 
        return res;//等于return target[key]
    }
}

function createSetter() {
    return function set(target, key, value, receiver) {
        const res = Reflect.set(target, key, value, receiver);
        //则需要判断,在utils.js中
        const isKeyExist = hasOwnProperty(target,key);
        const oldValue = target[key];
        //console.log('响应式设置' + key + '=' + value + ',' + target.length);//在设置的时候,需要把握是新增还是修改
        //则需要判断,在utils.js中
        if(!isKeyExist){
            console.log('响应式新增:'+value);

        }else if(!isEqual(value,oldValue)){//多个地方需要到这个判断
            console.log('响应式修改:'+key + '='+vaule);
        }
        return res;
    }
}

const mutableHandler = {
    get,
    set
}

export {
    mutableHandler
}

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { resolve } = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        path: resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: resolve(__dirname, 'src/index.html')
        })
    ],
    devServer: {
        contentBase: './'
    }
}

菜鸟学习源码中,如有错误,请各位大佬指出,谢谢大家~~QAQ