以下是笔者自己对实现mini-vue的个人理解
首先需要实现一个响应式的方法,即a变化b随之变化(b可以一开始可以是简单数据/后面可改成视图view)
1.使用到响应式的地方
//index.js
// const { effect,reactive} = require('@vue/reactivity')
// const {effectWatch,reactive} = require('./core/reactivity/index')
import {effectWatch,reactive} from './core/reactivity/index.js'
let a = reactive({
value:1
});
let b;
effectWatch(()=>{
//函数
//1.会自动执行一次
b=a.value+10;
console.log(b)
})
// a 响应式对象改变 函数又会执行一次
a.value = 30
2.构建响应式的类库,包括Dep依赖的收集/effectWatch执行函数/通过Proxy实现的响应式reactive
//core/reactivity/index.js
// const { effect } = require("@vue/reactivity")
let currentEffect;
//依赖
class Dep {
constructor(value) {
this.effects = new Set()
this._val = value
}
get value () {
this.depend()
return this._val
}
set value (newValue) {
this._val = newValue
this.notice()
}
//1.依赖的收集
depend () {
if (currentEffect) {
this.effects.add(currentEffect)
}
}
//2.依赖的发布
notice () {
this.effects.forEach(effect => {
effect()
});
}
}
export function effectWatch (effect) {
currentEffect = effect
effect()
currentEffect = null
}
const dep = new Dep(10)
// let b;
// effectWatch(() => {
// b = dep.value + 10
// console.log(b)
// })
// dep.value = 20
//vue2 Object.defineProperty
//vue3 Proxy
let targetMap = new Map()
function getDep (target, key) {
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let dep = depsMap.get(key)
if (!dep) {
dep = new Dep();
depsMap.set(key, dep)
}
return dep
}
export function reactive (raw) {
return new Proxy(raw, {
get (target, key) {
//key - dep
//dep 我们存储在哪里
const dep = getDep(target.key)
dep.depend()
return Reflect.get(target, key)
},
set (target, key, value) {
const dep = getDep(target.key)
const result = Reflect.set(target, key, value)
dep.notice()
return result
}
})
}
//一些测试代码
// const user = reactive({
// age: 19,
// name: 'zs'
// })
// let double;
// effectWatch(() => {
// console.log('---reactive-----')
// double = user.age
// console.log(double)
// }
// )
// user.age = 20
3.通过es moudle的方式进行调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script type="module" src="./index.js"></script>
<body>
</body>
</html>