国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【源碼系列#02】Vue3響應(yīng)式原理(Effect)

這篇具有很好參考價值的文章主要介紹了【源碼系列#02】Vue3響應(yīng)式原理(Effect)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項目專欄,硬核??推薦??
歡迎各位ITer關(guān)注點贊收藏??????

Vue3中響應(yīng)數(shù)據(jù)核心是 reactive , reactive 的實現(xiàn)是由 proxy 加 effect 組合,上一章節(jié)我們利用 proxy 實現(xiàn)了一個簡易版的 reactive,# 【源碼系列#01】Vue3響應(yīng)式原理(Reactive)。接下來讓我們一起手寫下 effect 的源碼

effect

effect 作為 reactive 的核心,主要負(fù)責(zé)收集依賴,更新依賴

在學(xué)習(xí) effect之前,我們再來看下這張圖

  • targetMap:存儲了每個 "響應(yīng)性對象屬性" 關(guān)聯(lián)的依賴;類型是 WeakMap
  • depsMap:存儲了每個屬性的依賴;類型是 Map
  • dep:存儲了我們的 effects ,一個 effects 集,這些 effect 在值發(fā)生變化時重新運行;類型是 Set

【源碼系列#02】Vue3響應(yīng)式原理(Effect)

編寫effect函數(shù)

// 當(dāng)前正在執(zhí)行的effect
export let activeEffect = undefined

export class ReactiveEffect {
  // @issue2
  // 這里表示在實例上新增了parent屬性,記錄父級effect
  public parent = null
  // 記錄effect依賴的屬性
  public deps = []
  // 這個effect默認(rèn)是激活狀態(tài)
  public active = true

  // 用戶傳遞的參數(shù)也會傳遞到this上 this.fn = fn
  constructor(public fn, public scheduler) {}

  // run就是執(zhí)行effect
  run() {
    // 這里表示如果是非激活的情況,只需要執(zhí)行函數(shù),不需要進(jìn)行依賴收集
    if (!this.active) {
      return this.fn()
    }
    // 這里就要依賴收集了 核心就是將當(dāng)前的effect 和 稍后渲染的屬性關(guān)聯(lián)在一起
    try {
      // 記錄父級effect
      this.parent = activeEffect
      activeEffect = this
      // 當(dāng)稍后調(diào)用取值操作的時候 就可以獲取到這個全局的activeEffect了
      return this.fn()
    } finally {
      // 還原父級effect
      activeEffect = this.parent
    }
  }
}

export function effect(fn, options: any = {}) {
  // 這里fn可以根據(jù)狀態(tài)變化 重新執(zhí)行, effect可以嵌套著寫
  const _effect = new ReactiveEffect(fn) // 創(chuàng)建響應(yīng)式的effect
  // issue1
  _effect.run() // 默認(rèn)先執(zhí)行一次
}

@issue1 effect 默認(rèn)會先執(zhí)行一次

依賴收集

const targetMap = new WeakMap()
export function track(target, type, key) {
  // @issue3
  // 我們只想在我們有activeEffect時運行這段代碼
  if (!activeEffect) return 
  
  let depsMap = targetMap.get(target) // 第一次沒有
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key) // key -> name / age
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  // 單向指的是 屬性記錄了effect, 反向記錄,應(yīng)該讓effect也記錄他被哪些屬性收集過,這樣做的好處是為了可以清理
  trackEffects(dep)
}

export function trackEffects(dep) {
  if (activeEffect) {
    let shouldTrack = !dep.has(activeEffect) // 去重了
    if (shouldTrack) {
      dep.add(activeEffect)
      // @issue4
      // 存放的是屬性對應(yīng)的set
      activeEffect.deps.push(dep) // 讓effect記錄住對應(yīng)的dep, 稍后清理的時候會用到
    }
  }
}

@issue3 當(dāng)activeEffect有值時,即只在effect運行時執(zhí)行track依賴收集

@issue4 雙向記錄 ,一個屬性對應(yīng)多個effect,一個effect對應(yīng)多個屬性

一個屬性對應(yīng)多個 effect: 在之前的 depsMap 圖中,我們得知,一個屬性映射一個 dep(即 effect 集合,類型為 Set)

一個effect對應(yīng)多個屬性: 在 effect 中,有一個 deps 屬性,她記錄了此 effect 依賴的每一個屬性所對應(yīng)的 dep。讓 effect 記錄對應(yīng)的 dep, 目的是在稍后清理的時候會用到

【源碼系列#02】Vue3響應(yīng)式原理(Effect)

觸發(fā)更新

export function trigger(target, type, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return // 觸發(fā)的值不在模板中使用

  let effects = depsMap.get(key) // 找到了屬性對應(yīng)的effect

  // 永遠(yuǎn)在執(zhí)行之前 先拷貝一份來執(zhí)行, 不要關(guān)聯(lián)引用
  if (effects) {
    triggerEffects(effects)
  }
}
export function triggerEffects(effects) {
  effects.forEach(effect => {
    // 我們在執(zhí)行effect的時候 又要執(zhí)行自己,那我們需要屏蔽掉,不要無限調(diào)用,【避免由activeEffect觸發(fā)trigger,再次觸發(fā)當(dāng)前effect。 activeEffect -> fn -> set -> trigger -> 當(dāng)前effect】
    // @issue5
    if (effect !== activeEffect) {
      effect.run() // 否則默認(rèn)刷新視圖
    }
  })
}

@issue5 避免由run觸發(fā)trigger,無限遞歸循環(huán)

我們在執(zhí)行 effect 的時候,又要執(zhí)行自己,那我們需要屏蔽掉,不要無限調(diào)用【避免由 activeEffect 觸發(fā) trigger,再次觸發(fā)當(dāng)前 effect。 activeEffect -> fn -> set -> trigger -> 當(dāng)前effect】

舉個栗子

const { effect, reactive } = VueReactivity
const data = { name: '柏成', age: 13, address: { num: 517 } }
const state = reactive(data)
// vue3中的代理都是用proxy來解決的

// 此effect函數(shù)默認(rèn)會先執(zhí)行一次, 對響應(yīng)式數(shù)據(jù)取值(取值的過程中數(shù)據(jù)會依賴于當(dāng)前的effect)
effect(() => {
  state.age = Math.random()
  document.getElementById('app').innerHTML = state.name + '今年' + state.age + '歲了'
})

// 稍后name和age變化會重新執(zhí)行effect函數(shù)
setTimeout(() => {
  state.age = 18
}, 1000)

分支切換與cleanup

// 每次執(zhí)行effect的時候清理一遍依賴,再重新收集,雙向清理
function cleanupEffect(effect) {
  // deps 里面裝的是name對應(yīng)的effect, age對應(yīng)的effect
  const { deps } = effect
  for (let i = 0; i < deps.length; i++) {
    // 解除effect,重新依賴收集
    deps[i].delete(effect)
  }
  effect.deps.length = 0
}

export class ReactiveEffect {
  // @issue3
  // 這里表示在實例上新增了parent屬性,記錄父級effect
  public parent = null
  // 記錄effect依賴的屬性
  public deps = []
  // 這個effect默認(rèn)是激活狀態(tài)
  public active = true

  // 用戶傳遞的參數(shù)也會傳遞到this上 this.fn = fn
  constructor(public fn, public scheduler) {} // @issue8 - scheduler

  // run就是執(zhí)行effect
  run() {
    // 這里表示如果是非激活的情況,只需要執(zhí)行函數(shù),不需要進(jìn)行依賴收集
    if (!this.active) {
      return this.fn()
    }
    // 這里就要依賴收集了 核心就是將當(dāng)前的effect 和 稍后渲染的屬性關(guān)聯(lián)在一起
    try {
      // 記錄父級effect
      this.parent = activeEffect
      activeEffect = this
      // 這里我們需要在執(zhí)行用戶函數(shù)之前將之前收集的內(nèi)容清空
      cleanupEffect(this) // @issue6
      // 當(dāng)稍后調(diào)用取值操作的時候 就可以獲取到這個全局的activeEffect了
      return this.fn() // @issue1
    } finally {
      // 還原父級effect
      activeEffect = this.parent
    }
  }
}

export function triggerEffects(effects) {
  // 先拷貝,防止死循環(huán),new Set 后產(chǎn)生一個新的Set
  effects = new Set(effects) // @issue7
  effects.forEach(effect => {
    // 我們在執(zhí)行effect的時候 又要執(zhí)行自己,那我們需要屏蔽掉,不要無限調(diào)用,【避免由activeEffect觸發(fā)trigger,再次觸發(fā)當(dāng)前effect。 activeEffect -> fn -> set -> trigger -> 當(dāng)前effect】
    if (effect !== activeEffect) {
      effect.run() // 否則默認(rèn)刷新視圖
    }
  })
}

@issue6 分支切換 - cleanupEffect。我們需要在執(zhí)行用戶函數(shù)之前將之前收集的內(nèi)容清空,雙向清理,在渲染時我們要避免副作用函數(shù)產(chǎn)生的遺留,舉個栗子,我們再次修改name,原則上不應(yīng)更新頁面

每次副作用函數(shù)執(zhí)行時,可以先把它從所有與之關(guān)聯(lián)的依賴集合中刪除。當(dāng)副作用函數(shù)執(zhí)行完畢后,響應(yīng)式數(shù)據(jù)會與副作用函數(shù)之間建立新的依賴關(guān)系,而分支切換后,與副作用函數(shù)沒有依賴關(guān)系的響應(yīng)式數(shù)據(jù)則不會再建立依賴,這樣副作用函數(shù)遺留的問題就解決了;

const { effect, reactive } = VueReactivity
const state = reactive({ flag: true, name: '柏成', age: 24 })

effect(() => {
  // 我們期望的是每次執(zhí)行effect的時候都可以清理一遍依賴,重新收集
  // 副作用函數(shù) (effect執(zhí)行渲染了頁面)
  console.log('render')
  document.body.innerHTML = state.flag ? state.name : state.age
})

setTimeout(() => {
  state.flag = false
  setTimeout(() => {
    // 修改name,原則上不更新頁面
    state.name = '李'
  }, 1000)
}, 1000)

@issue7 分支切換 - 死循環(huán)。遍歷 set 對象時,先 delete 再 add,會出現(xiàn)死循環(huán)

在調(diào)用循環(huán)遍歷 Set 集合時,如果一個值已經(jīng)被訪問過了,但該值被刪除,并重新添加到集合,如果此時循環(huán)遍歷沒有結(jié)束,那該值會被重新訪問

參考資料:ECMAScript Language Specification

【源碼系列#02】Vue3響應(yīng)式原理(Effect)

提示:語言規(guī)范說的是forEach時是這樣的,實測 for of 遍歷Set會有同樣的問題。

看一下 triggerEffects 方法,遍歷了 effects

export function triggerEffects(effects) {
  effects.forEach(effect => { effect.run() })
}

effect.run 方法中

  • 執(zhí)行 cleanupEffect(effect),清理一遍依賴
deps[i].delete(effect) 
  • 執(zhí)行 this.fn(),重新執(zhí)行函數(shù),重新收集依賴
// track() 方法中
dep.add(activeEffect) // 將副作用函數(shù)activeEffect添加到響應(yīng)式依賴中

解決方法:

let effect = () => {};
let deps = new Set([effect])
deps.forEach(item=>{
  console.log('>>>')
  deps.delete(effect); 
  deps.add(effect)
}); // 這樣就導(dǎo)致死循環(huán)了

// 解決方案如下,先拷貝一份,遍歷的Set對象 和 操作(delete、add)的Set對象不是同一個即可
let effect = () => {};
let deps = new Set([effect])
const newDeps = new Set(deps) 
newDeps.forEach(item=>{
  console.log('>>>')
  deps.delete(effect); 
  deps.add(effect)
}); 

effect嵌套

// 當(dāng)前正在執(zhí)行的effect
export let activeEffect = undefined

export class ReactiveEffect {
  // @issue2
  // 這里表示在實例上新增了parent屬性,記錄父級effect
  public parent = null
  // 記錄effect依賴的屬性
  public deps = []
  // 這個effect默認(rèn)是激活狀態(tài)
  public active = true

  // 用戶傳遞的參數(shù)也會傳遞到this上 this.fn = fn
  constructor(public fn, public scheduler) {}

  // run就是執(zhí)行effect
  run() {
    // 這里表示如果是非激活的情況,只需要執(zhí)行函數(shù),不需要進(jìn)行依賴收集
    if (!this.active) {
      return this.fn()
    }
    // 這里就要依賴收集了 核心就是將當(dāng)前的effect 和 稍后渲染的屬性關(guān)聯(lián)在一起
    try {
      // 記錄父級effect
      this.parent = activeEffect
      activeEffect = this
      // 當(dāng)稍后調(diào)用取值操作的時候 就可以獲取到這個全局的activeEffect了
      return this.fn()
    } finally {
      // 還原父級effect
      activeEffect = this.parent
    }
  }
}

export function effect(fn, options: any = {}) {
  // 這里fn可以根據(jù)狀態(tài)變化 重新執(zhí)行, effect可以嵌套著寫
  const _effect = new ReactiveEffect(fn) // 創(chuàng)建響應(yīng)式的effect
  // issue1
  _effect.run() // 默認(rèn)先執(zhí)行一次
}

@issue2 利用 parent 解決effect嵌套問題,effect 嵌套的場景在 Vue.js 中常常出現(xiàn),如:Vue中的渲染函數(shù)(render)就是在一個effect中執(zhí)行的,嵌套組件就會伴隨著嵌套 effect

  1. 解決effect嵌套問題----棧方式------------------------vue2/vue3.0初始版本
// 運行effect,此effect入棧,運行完畢,最后一個effect出棧,屬性關(guān)聯(lián)棧中的最后一個effect
[e1] -> [e1,e2] -> [e1]
effect(() => {   // activeEffect = e1
  state.name     // name -> e1
  effect(() => { // activeEffect = e2
    state.age    // age -> e2
  })
                 // activeEffect = e1
  state.address  // address = e1
})
  1. 解決effect嵌套問題----樹形結(jié)構(gòu)方式----------------vue3后續(xù)版本
// 這個執(zhí)行流程 就類似于一個樹形結(jié)構(gòu)
effect(()=>{       // parent = null  activeEffect = e1
  state.name       // name -> e1
  effect(()=>{     // parent = e1  activeEffect = e2
     state.age     // age -> e2
     effect(()=> { // parent = e2  activeEffect = e3
        state.sex  // sex -> e3
     })            // activeEffect = e2
  })               // activeEffect = e1

  state.address    // address -> e1

  effect(()=>{     // parent = e1   activeEffect = e4
    state.age      // age -> e4
  })
})

停止effect和調(diào)度執(zhí)行


export class ReactiveEffect {
  // @issue8 - stop
  stop() {
    if (this.active) {
      this.active = false
      cleanupEffect(this) // 停止effect的收集
    }
  }
}

export function effect(fn, options: any = {}) {
  // 這里fn可以根據(jù)狀態(tài)變化 重新執(zhí)行, effect可以嵌套著寫
  const _effect = new ReactiveEffect(fn, options.scheduler) // 創(chuàng)建響應(yīng)式的effect @issue8 - scheduler
  _effect.run() // 默認(rèn)先執(zhí)行一次

  // @issue8 - stop
  // 綁定this,run方法內(nèi)的this指向_effect,若不綁定,這樣調(diào)用run方法時,runner(),則指向undefined
  const runner = _effect.run.bind(_effect)
  // 將effect掛載到runner函數(shù)上,調(diào)用stop方式時可以這樣調(diào)用 runner.effect.stop()
  runner.effect = _effect
  return runner
}


export function triggerEffects(effects) {
  // 先拷貝,防止死循環(huán),new Set 后產(chǎn)生一個新的Set
  effects = new Set(effects) // @issue7
  effects.forEach(effect => {
    // 我們在執(zhí)行effect的時候 又要執(zhí)行自己,那我們需要屏蔽掉,不要無限調(diào)用,【避免由activeEffect觸發(fā)trigger,再次觸發(fā)當(dāng)前effect。 activeEffect -> fn -> set -> trigger -> 當(dāng)前effect】
    if (effect !== activeEffect) {
      // @issue8 - scheduler
      if (effect.scheduler) {
        effect.scheduler() // 如果用戶傳入了調(diào)度函數(shù),則執(zhí)行調(diào)度函數(shù)
      } else {
        effect.run() // 否則默認(rèn)刷新視圖
      }
    }
  })
}

如何使用 stop 和 scheduler ?舉個小栗子

  • 當(dāng)我們調(diào)用 runner.effect.stop() 時,就雙向清理了 effect 的所有依賴,后續(xù) state.age 發(fā)生變化后,將不再重新更新頁面
  • 基于 scheduler 調(diào)度器,我們可以控制頁面更新的周期,下面例子中,會在1秒后,頁面由 30 變?yōu)?5000
let waiting = false
const { effect, reactive } = VueReactivity
const state = reactive({ flag: true, name: 'jw', age: 30, address: { num: 10 } })
let runner = effect(
  () => {
    // 副作用函數(shù) (effect執(zhí)行渲染了頁面)
    document.body.innerHTML = state.age
  },
  {
    scheduler() {
      // 調(diào)度 如何更新自己決定
      console.log('run')
      if (!waiting) {
        waiting = true
        setTimeout(() => {
          runner()
          waiting = false
        }, 1000)
      }
    },
  },
)

// 清理 effect 所有依賴,state.age 發(fā)生變化后,將不再重新更新頁面
// runner.effect.stop()

state.age = 1000
state.age = 2000
state.age = 3000
state.age = 4000
state.age = 5000

effect.ts

完整代碼如下

/**
 * @issue1 effect默認(rèn)會先執(zhí)行一次
 * @issue2 activeEffect 只在effect運行時執(zhí)行track保存
 * @issue3 parent 解決effect嵌套問題
 * @issue4 雙向記錄  一個屬性對應(yīng)多個effect,一個effect對應(yīng)多個屬性 √
 * @issue5 避免由run觸發(fā)trigger,遞歸循環(huán)
 * @issue6 分支切換 cleanupEffect
 * @issue7 分支切換 死循環(huán),set循環(huán)中,先delete再add,會出現(xiàn)死循環(huán)
 * @issue8 自定義調(diào)度器 類似Vue3中的effectScope stop 和 scheduler
 */

// 當(dāng)前正在執(zhí)行的effect
export let activeEffect = undefined

// @issue6
// 每次執(zhí)行effect的時候清理一遍依賴,再重新收集,雙向清理
function cleanupEffect(effect) {
  // deps 里面裝的是name對應(yīng)的effect, age對應(yīng)的effect
  const { deps } = effect
  for (let i = 0; i < deps.length; i++) {
    // 解除effect,重新依賴收集
    deps[i].delete(effect)
  }
  effect.deps.length = 0
}

export class ReactiveEffect {
  // @issue3
  // 這里表示在實例上新增了parent屬性,記錄父級effect
  public parent = null
  // 記錄effect依賴的屬性
  public deps = []
  // 這個effect默認(rèn)是激活狀態(tài)
  public active = true

  // 用戶傳遞的參數(shù)也會傳遞到this上 this.fn = fn
  constructor(public fn, public scheduler) {} // @issue8 - scheduler

  // run就是執(zhí)行effect
  run() {
    // 這里表示如果是非激活的情況,只需要執(zhí)行函數(shù),不需要進(jìn)行依賴收集
    if (!this.active) {
      return this.fn()
    }
    // 這里就要依賴收集了 核心就是將當(dāng)前的effect 和 稍后渲染的屬性關(guān)聯(lián)在一起
    try {
      // 記錄父級effect
      this.parent = activeEffect
      activeEffect = this
      // 這里我們需要在執(zhí)行用戶函數(shù)之前將之前收集的內(nèi)容清空
      cleanupEffect(this) // @issue6
      // 當(dāng)稍后調(diào)用取值操作的時候 就可以獲取到這個全局的activeEffect了
      return this.fn() // @issue1
    } finally {
      // 還原父級effect
      activeEffect = this.parent
    }
  }
  // @issue8 - stop
  stop() {
    if (this.active) {
      this.active = false
      cleanupEffect(this) // 停止effect的收集
    }
  }
}

export function effect(fn, options: any = {}) {
  // 這里fn可以根據(jù)狀態(tài)變化 重新執(zhí)行, effect可以嵌套著寫
  const _effect = new ReactiveEffect(fn, options.scheduler) // 創(chuàng)建響應(yīng)式的effect @issue8 - scheduler
  _effect.run() // 默認(rèn)先執(zhí)行一次

  // @issue8 - stop
  // 綁定this,run方法內(nèi)的this指向_effect,若不綁定,這樣調(diào)用run方法時,runner(),則指向undefined
  const runner = _effect.run.bind(_effect)
  // 將effect掛載到runner函數(shù)上,調(diào)用stop方式時可以這樣調(diào)用 runner.effect.stop()
  runner.effect = _effect
  return runner
}

// 對象 某個屬性 -》 多個effect
// WeakMap = {對象:Map{name:Set-》effect}}
// {對象:{name:[]}}
// 多對多  一個effect對應(yīng)多個屬性, 一個屬性對應(yīng)多個effect
const targetMap = new WeakMap()
export function track(target, type, key) {
  // 我們只想在我們有activeEffect時運行這段代碼
  if (!activeEffect) return // @issue2
  let depsMap = targetMap.get(target) // 第一次沒有
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key) // key -> name / age
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  // 單向指的是 屬性記錄了effect, 反向記錄,應(yīng)該讓effect也記錄他被哪些屬性收集過,這樣做的好處是為了可以清理
  trackEffects(dep)
}

export function trackEffects(dep) {
  if (activeEffect) {
    let shouldTrack = !dep.has(activeEffect) // 去重了
    if (shouldTrack) {
      dep.add(activeEffect)
      // @issue4
      // 存放的是屬性對應(yīng)的set
      activeEffect.deps.push(dep) // 讓effect記錄住對應(yīng)的dep, 稍后清理的時候會用到
    }
  }
}

export function trigger(target, type, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return // 觸發(fā)的值不在模板中使用

  let effects = depsMap.get(key) // 找到了屬性對應(yīng)的effect

  // 永遠(yuǎn)在執(zhí)行之前 先拷貝一份來執(zhí)行, 不要關(guān)聯(lián)引用
  if (effects) {
    triggerEffects(effects)
  }
}
export function triggerEffects(effects) {
  // 先拷貝,防止死循環(huán),new Set 后產(chǎn)生一個新的Set
  effects = new Set(effects) // @issue7
  effects.forEach(effect => {
    // 我們在執(zhí)行effect的時候,有時候會改變屬性,那我們需要屏蔽掉,不要無限調(diào)用,【避免由activeEffect觸發(fā)trigger,再次觸發(fā)當(dāng)前effect。 activeEffect -> fn -> set -> trigger -> 當(dāng)前effect】
    // @issue5
    if (effect !== activeEffect) {
      // @issue8 - scheduler
      if (effect.scheduler) {
        effect.scheduler() // 如果用戶傳入了調(diào)度函數(shù),則執(zhí)行調(diào)度函數(shù)
      } else {
        effect.run() // 否則默認(rèn)刷新視圖
      }
    }
  })
}

參考資料

Vue3響應(yīng)式系統(tǒng)實現(xiàn)原理(二) - CherishTheYouth - 博客園文章來源地址http://www.zghlxwxcb.cn/news/detail-747377.html

到了這里,關(guān)于【源碼系列#02】Vue3響應(yīng)式原理(Effect)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • vue3源碼(二)reactive&effect

    vue3源碼(二)reactive&effect

    reactive 方法會將對象變成 proxy 對象, effect 中使用 reactive 對象時會進(jìn)行依賴收集,稍后屬性變化時會重新執(zhí)行 effec t函數(shù)。 1.1 get、set基礎(chǔ)實現(xiàn) 如下圖,如果采用 target[key] 方法,獲取 aliasName 時 不會觸發(fā) name 的 get 1.2 完善重復(fù) 響應(yīng)式數(shù)據(jù)緩存,防止重復(fù)代理 使用 map , key

    2024年01月25日
    瀏覽(21)
  • 【手撕源碼】vue3響應(yīng)式原理解析(文末抽獎)

    【手撕源碼】vue3響應(yīng)式原理解析(文末抽獎)

    ?? 個人主頁: 不叫貓先生 ???♂? 作者簡介:2022年度博客之星前端領(lǐng)域TOP 2,前端領(lǐng)域優(yōu)質(zhì)作者、阿里云專家博主,專注于前端各領(lǐng)域技術(shù),共同學(xué)習(xí)共同進(jìn)步,一起加油呀! ??優(yōu)質(zhì)專欄:vue3從入門到精通、TypeScript從入門到實踐 ?? 資料領(lǐng)?。呵岸诉M(jìn)階資料以及文中源

    2024年02月03日
    瀏覽(21)
  • 【源碼系列#03】Vue3計算屬性原理(Computed)

    【源碼系列#03】Vue3計算屬性原理(Computed)

    專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項目專欄,硬核??推薦?? 歡迎各位ITer關(guān)注點贊收藏?????? 傳入一個 getter 函數(shù),返回一個默認(rèn)不可手動修改的 ref 對象 或者傳入一個擁有 get 和 set 函數(shù)的對象,創(chuàng)建一個可手動修改的計算狀態(tài) @issue1 compute

    2024年02月05日
    瀏覽(51)
  • 【源碼系列#04】Vue3偵聽器原理(Watch)

    專欄分享:vue2源碼專欄,vue3源碼專欄,vue router源碼專欄,玩具項目專欄,硬核??推薦?? 歡迎各位ITer關(guān)注點贊收藏?????? 偵聽一個或多個響應(yīng)式數(shù)據(jù)源,并在數(shù)據(jù)源變化時調(diào)用所給的回調(diào)函數(shù) 第一個參數(shù)可以是不同形式的“數(shù)據(jù)源”:它可以是一個 ref (包括計算屬性

    2024年02月04日
    瀏覽(94)
  • 前端開發(fā)攻略---從源碼角度分析Vue3的Propy比Vue2的defineproperty到底好在哪里。一篇文章讓你徹底弄懂響應(yīng)式原理。

    前端開發(fā)攻略---從源碼角度分析Vue3的Propy比Vue2的defineproperty到底好在哪里。一篇文章讓你徹底弄懂響應(yīng)式原理。

    Vue的響應(yīng)式到底要干什么? 無非就是要知道當(dāng)你 讀取 對象的時候,要知道它讀了。要做一些別的事情 無非就是要知道當(dāng)你 修改 對象的時候,要知道它改了。要做一些別的事情 所以要想一個辦法, 把讀取和修改的動作變成一個函數(shù) ,讀取和修改的時候分別調(diào)用對應(yīng)的函數(shù)

    2024年04月17日
    瀏覽(34)
  • vue3響應(yīng)式原理

    vue3響應(yīng)式原理

    Vue 3 中的響應(yīng)式原理是通過使用 ES6 的 Proxy 對象來實現(xiàn)的。在 Vue 3 中,每個組件都有一個響應(yīng)式代理對象,當(dāng)組件中的數(shù)據(jù)發(fā)生變化時,代理對象會立即響應(yīng)并更新視圖。 具體來說,當(dāng)一個組件被創(chuàng)建時,Vue 會為組件的 data 對象創(chuàng)建一個響應(yīng)式代理對象。這個代理對象可以

    2024年02月15日
    瀏覽(37)
  • Vue3 數(shù)據(jù)響應(yīng)式原理

    核心: 通過Proxy(代理): 攔截對data任意屬性的任意(13種)操作, 包括屬性值的讀寫, 屬性的添加, 屬性的刪除等… 通過 Reflect(反射): 動態(tài)對被代理對象的相應(yīng)屬性進(jìn)行特定的操作 Vue3的響應(yīng)式比Vue2好在哪里? 效率更高了,Vue2中假設(shè)監(jiān)聽某個對象,該對象中有一萬個屬性,他要循

    2024年02月11日
    瀏覽(20)
  • Vue3響應(yīng)式原理 私

    Vue3響應(yīng)式原理 私

    響應(yīng)式的本質(zhì):當(dāng)數(shù)據(jù)變化后會自動執(zhí)行某個函數(shù)映射到組件,自動觸發(fā)組件的重新渲染。 響應(yīng)式的實現(xiàn)方式就是劫持?jǐn)?shù)據(jù),Vue3的reactive就是通過Proxy劫持?jǐn)?shù)據(jù),由于劫持的是整個對象,所以可以檢測到任何對象的修改,彌補了2.0的不足。 名詞解釋: **副作用函數(shù):**函數(shù)的

    2024年02月10日
    瀏覽(21)
  • 手寫Vue3響應(yīng)式數(shù)據(jù)原理

    手寫Vue3響應(yīng)式數(shù)據(jù)原理

    我們想要對一個對象數(shù)據(jù)進(jìn)行處理,從而實現(xiàn)更改dom。但如何更改對一個對象數(shù)據(jù)進(jìn)行更改呢? vue2 的雙向數(shù)據(jù)綁定是利?ES5 的?個 API ,Object.defineProperty()對數(shù)據(jù)進(jìn)?劫持 結(jié)合 發(fā)布訂閱模式的?式來實現(xiàn)的。 vue3 中使?了 ES6 的 ProxyAPI 對數(shù)據(jù)代理,通過 reactive() 函數(shù)給每?

    2024年02月11日
    瀏覽(19)
  • Vue3響應(yīng)式源碼實現(xiàn)

    Vue3響應(yīng)式源碼實現(xiàn)

    初始化項目結(jié)構(gòu) reactive.ts effect.ts 測試 執(zhí)行 tsc 轉(zhuǎn)成 js 代碼,沒有 tsc 的全局安裝 typescript 新建 index.js ,分別引入 effect.js 和 reactive.js 新建 index.html 然后再根目錄執(zhí)行 安裝依賴 然后新建 webpack.config.js 執(zhí)行命令啟動項目

    2024年02月09日
    瀏覽(18)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包