Vue3双向绑定原理
核心是使用proxy
进行数据劫持。
具体实现
实现reactive,
代码使用Webpack
构建:
- 创建目录
- 在
./reactivity/index.js
文件中公开方法
// ./reactivity/index.js
import {
reactive } from './reactive'
export {
reactive
}
./reactivity/rective.js
中实现核心代码
在vue中reactive({})
是传入一个对象到reactive
方法中进行数据劫持,数据劫持有些逻辑所以我们出单独的方法createReactiveObject
// ./reactivity/rective.js
import {
mutableHandler } from "./mutableHandler";
function reactive(target){
return createReactiveObject(target, mutableHandler)
// mutableHandle 可变的,不确定有多少属性,单独提一个文件
}
createReactiveObject
的两个参数:target
劫持的对象,baseHandle
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 的行为
new Proxy(target, {
get(){
},
set(){
}
})
- 实现
createReactiveObject
// ./reactivity/rective.js
import {
isObject } from "../shared/utils";
//自定义isObject方法 判断是否是一个对象
function createReactiveObject(target, baseHandle){
if (!isObject(target)) {
return target
}
const observer = new Proxy(target, baseHandle)
return observer;
}
- 实现proxy中
get
,set
// ./reactivity/mutableHandler.js
import {
reactive } from "./reactive";
import {
hasOwnProperty, isEqual, isObject } from "../shared/utils";
const get = createGetter()
const set = createSetter()
function createGetter () {
return function get (target, key, reactiver) {
const res = Reflect.get(target, key, reactiver)
console.log('响应式获取' + target[key])
//如果res对象 就进行递归
if (isObject(res)) {
return reactive(res)
}
return res; //return target[key]
}
}
function createSetter () {
return function set (target, key, value, reactiver) {
const isKeyExist = hasOwnProperty(target, key)// 自定义hasOwnProperty 判断是否为新增属性
const oldValue = target[key]
const res = Reflect.set(target, key, value, reactiver)
if(!isKeyExist) {
console.log('响应式新增' + value)
} else if (isEqual(value, oldValue)) {
console.log('响应式修改' + key + '=' + value)
}
return res
}
}
//返回值为一个对象
const mutableHandler = {
get,
set
}
export {
mutableHandler
}
工具函数实现
// ../shared/utils.js
function isObject (value) {
return typeof value === 'object' && value !== null
}
function hasOwnProperty(target, key) {
return Object.prototype.hasOwnProperty.call(target,key)
}
function isEqual (newValue, oldValue) {
return newValue === oldValue
}
export {
isObject,
hasOwnProperty,
isEqual
}