(1)手写mini-vue,实现一个响应式库

35 阅读1分钟

以下是笔者自己对实现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>

4.结果 b会随着a的变化而进行变化

image.png