vue.js设计与实现(分支切换与cleanup)

发布于:2024-04-01 ⋅ 阅读:(63) ⋅ 点赞:(0)

如存在三元运算符时,怎么处理

// 原始数据
const data = { text: 'hello world',ok:true}

// 副作用函数存在三元运算符
effect(function effectFn(){
    document.body.innerText = obj.ok ? obj.text : 'not'
})

// 理解如此,obj.ok和obj.text都会绑定effectFn函数,所以不管obj.ok 是true还是false ,obj.text值改变都会执行effectFn副作用函数,然而当obj.ok为false时,obj.text值无论怎么改变,都不应该执行effectFn副作用函数。
解决方案:每次执行副作用 函数,可以先把它从所有与之关联的依赖集合中删除。当副作用函数执行完后,会重新建立关系。
// 用一个全局变量储存被注册的副作用函数
let activeEffect

// effect 函数用于注册副作用函数
function effect(fn){
  // 当 effectFn 执行时,将其设置为当前激活的副作用函数
  const effectFn = ()=>{
    // 调用cleanup完成清除工作
    cleanup(effectFn)
    // 当调用effect注册副作用函数时,将副作用函数fn赋值给activeEffect
    activeEffect = effectFn
    // 执行副作用函数
    fn()
  }
  // activeEffect.deps 用来存储所有与被副作用函数相关的依赖集合
  effectFn.deps = []
  // 执行副作用函数
  effectFn()
}

// 清除工作
function cleanup(effectFn){
 // 遍历`effectFn.deps 数组
 for(let i=0; i< effectFn.deps.length; i++){
   // deps 是依赖集合
   const deps = effectFn.deps[i]

   // 将 effectFn 从依赖集合中移除
   deps.delete(effectFn)
 }
 // 最后需要重置 effectFn.deeps 数组
 effectFn.deps.length = 0
}

// 储存副作用函数的桶
const bucket = new WeakMap()

// 原始数据
const data = { text: 'hello world',ok:true}

// 对原始数据的代理
const obj = new Proxy(data,{
  // 拦截读取操作
  get(target,key){
    
    track(target,key)

    // 返回属性值
    return target[key]
  },
  // 拦截设置操作
  set(target,key,newValue){
    console.log('bucket:',bucket)
    // 设置属性值
    target[key] = newValue
   
    trigger(target,key)

    return true
  }
})

// 在 get 拦截函数内调用 track 函数追踪变化
function track(target,key){
  // 没有 activeEffect 直接 return
    if(!activeEffect) return target[key]
    // 根据 target 从 “桶” 中 取得 depsMap,它也是一个map 类型 key --》effects
    let depsMap = bucket.get(target)
    // 如果不存在 depsMap 那么新建一个Map 并与 target 关联
    if(!depsMap){
      bucket.set(target,(depsMap = new Map()))
    }
    // 再根据 key 从 depsMap 中取得 deps,它是一个 set 类型
    // 里面储存着所有与当前key 相关联的副作用函数,effects
    let deps = depsMap.get(key)
    // 如果 deps 不存在 同样新建一个set 并与 key 关联
    if(!deps){
      depsMap.set(key,(deps = new Set()))
    }
    // 最后将当前激活的副作用函数添加到“桶”
    deps.add(activeEffect)

    // deps 就是一个与当前副作用函数存在关联的依赖集合
    // 将其添加到activeEffect.deps 数组中
    activeEffect.deps.push(deps)  // 新增
}
// 在 set 拦截函数内调用 trigger 函数 触发变化
function trigger(target,key){
   // 根据 target 从桶中取得 depsMap,它是key --》effects
    const depsMap = bucket.get(target)
    if(!depsMap) return true
    // 根据 key 取得所有副作用函数 effects
    const effects = depsMap.get(key)

    // new Set 是为了防止 effectFn 执行时,进行无限的循环
    const effectsToRun = new Set(effects)
    effectsToRun.forEach(effectFn => effectFn())
    // 执行副作用函数
    // effects && effects.forEach(fn => fn())
}

// 执行副作用函数,触发读取
effect(function effectFn(){
    document.body.innerText = obj.ok ? obj.text : 'not'
})

// 1 秒后修改响应式数据
setTimeout(()=>{
  obj.text = 'hello vue3'
},1000)


setTimeout(()=>{
  obj.ok = false
},3000)
本文含有隐藏内容,请 开通VIP 后查看