從零寫乙個 Vue(六)元件化

2021-10-07 10:28:28 字數 4565 閱讀 8635

本篇是從零實現vue2系列第六篇,將在 yourvue 中實現 component。從這篇開始實現的內容,部落格上討論的就比較少了,不過啃原始碼肯定要啃完整。

將 main.js 中的內容一部分提取到元件 helloworld 中,在 yourvue 例項上註冊 helloworld 元件。

1const helloworld = ,

6    props:['message'],

7    template: `

8        9            array: }

10            }

11            addcount

12            }

13            deccount

14        

15    `,

16    methods:,

21        deccount()

25    }

26  }

27new yourvue(,

30    data:,

33    template: `

34      35        

36        parent button

37      

38    `,

39    methods:

43    }

44})

我們可以從流程上思考一下**發生了變化????

從 template -> ast -> gencode -> render 函式這個流程是沒有變化的,只不過其中有了乙個 tag 為hello-world的 vnode,所以需要在生成 vnode 的時候新增判斷,是 html 標籤還是自定義標籤。

1function createelement (tag, data={}, children=)else

8}

ishtmltag 就是直接判斷 tag 是否在所有 html 元素組成的列表裡,如果不是 html 標籤就執行 componenttovnode。

1export function componenttovnode(tag, data, children, vm)

5    const ctor = yourvue.extend(vm.$options.components[tag])

6    const name = tag

7    data.hooks = )

13            initprops(child, vnode.props.attrs)

14            child.$mount()

15        },

16        prepatch (oldvnode, vnode) 

24                child._props[key] = attrs[key]

25            }

26        }

27    }

28    const listeners = data.on

29    const vnode = new vnode(

30        `vue-component-$$` : ''}`,

31        data, undefined, undefined, undefined, vm,

32        

33    )

34    return vnode

35}

因為需要將元件定義的引數傳入 yourvue 例項,所以定義 ctor 繼承 yourvue,先將元件引數作為 extendoptions 傳入,在 ctor 的建構函式中,將 extendoptions 和 options 融合作為 _init 的引數。並將 ctor 快取,再次使用該元件時候可以直接從快取中讀取該元件對應的 ctor。

1export default class yourvue

4        const super = this

5        const superid = super.cid

6        const cachedctors = extendoptions._ctor || (extendoptions._ctor = {})

7        if (cachedctors[superid]) 

10        const sub = function vuecomponent (options) 

13        sub.prototype = object.create(super.prototype)

14        sub.prototype.constructor = sub

15        sub.cid = cid++

16        sub['super'] = super

17        sub.extend = super.extend

18        cachedctors[superid] = sub

19        return sub

20    }

21}

從 componenttovnode 最後可以看出來,返回的 vnode 的 tag 進行了重新命名,data 暫時有兩個 hooks,其餘引數都傳入了 vnode 的最後乙個引數 componentoptions 中。

1constructor(tag, data={}, children=, text='', elm, context, componentoptions)
vnode 建立好了,生成真實 dom 的時候就用到了 patch。在上篇文章中的 createelm 開始新增乙個 createcomponent 函式,在這個函式中會執行上面提到的 data.hooks.init。

1function createelm (vnode, parentelm, afterelm = undefined) 

5  ...

6} 7function createcomponent (vnode, parentelm, afterelm) 

13    if (isdef(vnode.componentinstance)) else if(parentelm)

20      return true

21    }

22  }

23}

再返回來看 hooks.init,其中初始化了 ctor,並傳入兩個引數標準 component 和記錄父 vnode。最後執行 $mount 函式,生成真實 dom。可以從上面**vnode.elm = vnode.componentinstance.vnode.elm發現,父元件中hello-worldcomponent 渲染的 elm,就是子元件的真實 dom。

1init(vnode))

6    initprops(child, vnode.props.attrs)

7    child.$mount()

8}

initprops(child, vnode.props.attrs)處理父元件傳入子元件的 props,initprops 定義如下。

1function initprops(vm, propsoptions)

3    for (const key in propsoptions) 

7        definereactive(props, key, propsoptions[key])

8        if (!(key in vm)) 

11    }

12}

將 propsoptions 傳遞來的變數通過響應式函式 definereactive 修改 props 的 get 和 set 方法,實現發布訂閱。然後通過 proxy 方法**,這樣就可以直接使用 this 來訪問 props 了。

prepatch 鉤子是在 patchvnode 中執行。

1function patchvnode(oldvnode, vnode)

5  let i

6  const data = vnode.props

7  if (isdef(data) && isdef(i = data.hooks) && isdef(i = i.prepatch)) 

10  ...

11}12

13prepatch (oldvnode, vnode) 

21        child._props[key] = attrs[key]

22    }

23}

將 componentinstance 賦給新的 vnode,將父元件傳遞的 props 最新值賦給 _props,觸發雙向繫結中的 set 函式。

這樣,component 從定義到轉換成真實 dom 以及父元件向子元件傳遞 props 的功能就基本完成了。

本篇**:

從零寫乙個Java WEB框架(一)

從乙個簡單的servlet專案開始起步。對每一層進行優化,然後形成乙個輕量級的框架。每一篇,都是針對專案的不足點進行優化的。專案已放上github 乙個非常基礎的servlet專案。基本功能是 對資料表 客戶表進行資料處理。例如 客戶的資料獲取 controller 層 獲取客戶端的資料 思路 通過...

從零寫乙個Java WEB框架(一)

從乙個簡單的servlet專案開始起步。對每一層進行優化,然後形成乙個輕量級的框架。每一篇,都是針對專案的不足點進行優化的。專案已放上github 乙個非常基礎的servlet專案。基本功能是 例如 客戶的資料獲取 controller 層 獲取客戶端的資料 思路 server 層中的獲取所有客戶資...

如何寫乙個Vue元件

寫的是以.vue結尾的單檔案元件的寫法,是基於webpack構建的專案。template 模板 js 邏輯 css 樣式 每個元件都有屬於自己的模板,js和樣式。如果將乙個頁面比喻成一間房子的話,元件就是房子裡的客廳 臥室 廚房 廁所。如果把廚房單獨拿出來的話,元件又可以是刀 油煙機.等等。就是說頁...