petite-vue源碼剖析-ref的工作原理

ref內部的工作原理十分簡單,其實就是將指令ref:refv-bind:ref標識的元素實例存儲到當前作用域的$refs對象中,那麼我們就可以通過this.$refs獲取對應的元素實例。但由於作用域繼承上有點小竅門,所以我們能從this.$refs獲取的元素實例還是需要注意一下。下面讓我爲你一一道來吧!

深入ref工作原理

//文件 ./src/directives/ref.ts

export const ref: Directive = ({
  el,
  ctx: {
    scope: { $refs }
  },
  get,
  effect
}) => {
  let prevRef: any
  effect(() => {
    // 獲取指向元素的屬性名稱
    const ref = get()
    $refs[ref] = el
    // 由於屬性名稱是可以動態生成的(:ref="name"),若新舊對應的屬性名稱不同,則清理舊屬性
    if (prevRef && ref != prevRef) {
      delete $refs[prevRef]
    }
    prevRef = ref
  })

  return () => {
    prevRef && delete $refs[prevRef]
  }
}

這段實現是不是言簡意賅呢?現在讓我們把目光轉向上下文對象(Context)的構建吧

//文件 ./src/context.ts

export const createScopedContext = (ctx: Context, data = {}) => {
  onst parentScope = ctx.scope
  const mergedScope = Object.create(parentScope)
  Object.defineProperties(mergedScope, Object.getOwnPropertyDescriptors(data))
  // $refs構成$refs對象的原型鏈
  mergedScope.$refs = Object.create(parentScope.$refs)
  // ......
}

$refs構成$refs對象的原型鏈,那麼我們就可以這樣引用元素實例

createApp({
  App: {
    $template: `
    <div ref="container">
      <div v-scope="Modal"></div>
    </div>
    `,
    Modal: {
      $template: `
      <button @click="handleHide">Hide</button>
      `,
      handleHide() {
        this.$refs.container.style.display = 'none'
      }
    }
  }
}).mount('[v-scope]')

總結

下一篇《petite-vue源碼剖析-優化手段template詳解》我們將着手解決petite-vue在線模板和在線渲染造成用戶體驗待優化的問題,敬請期待。
尊重原創,轉載請註明來自:https://www.cnblogs.com/fsjohnhuang/p/16006899.html 肥仔John

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章