上篇博客,我們得到表達式的內容了,那麼接下來我們想幹什麼?是不是想把挑出來的這段表達式,給它解析了呀?
我們在之前的博客中也有做過,用的是 eval。
首先肯定一點,其實也沒什麼特別高明的辦法,要麼 eval,要麼就 function,就這兩種辦法。
不過現在,我們準備重新的再來這一下這個事,爲什麼呢?
首先,在我們編譯 s 這個字符串的過程當中,別的都可以忽略,但起碼得有數據吧?
那麼這個 VText,它身上有數據嗎?並沒有。
那誰身上有?是不是 VComponent 身上有,所有的數據都在 VComponent 身上。相當於不管是 VElement,還是 VNode,它們其實都是沒有數據的狀態,都是一個純節點。
那麼如果想要數據,就得找 VComponent,所以這時候,我們就得知道,這個節點它所對應的那個 component 是誰。
那麼我們就直接來了,對於 VText 和 VElement 它們兩個來說,我們還需要一個額外的參數。
什麼參數呢?那就是我的 component 是誰:
因爲如果不知道這個的話,其實是很費勁的。
然後這個 component 需要做幾件事:
首先,我們 assert 一下,你必須得給我,你不給我就幹不了活,因爲數據都沒,啥都做不了。
然後我們要把它給存起來:
以及 VElement 這邊,我們也需要 component ,因爲你得告訴我,我屬於誰,然後我在藉助它的數據,去編譯我的東西:
當然,如果在這時候我們直接就這麼運行,是會報錯的:
其實就是 VText 這邊報的,因爲我們並沒有傳 component,那這個怎麼辦呢?
非常簡單,首先我們別忘了,VText 是誰創建出來的?其實 VText 是 VElement 創建出來的,爲什麼這麼說呢?
因爲我們 VElement 裏面的 createChildren,它是要遞歸的往裏面創建的,並且它在遞歸的過程當中,是不是順便的就把我們的那個 VText 也創建出來了。
所以說白了,它是從 VElement 裏面來的。
所以在這種情況下,事情就變的非常的好辦,我們就可以在 createChildren 裏面,給它加個參數:
並且,分別傳給我的子元素 VElement,和子文本元素 VText:
當然這時候又有一個問題了,你可以看到頁面上還是報錯:
這回的報錯,其實是 VElement,因爲我們現在並沒有 component 這個東西。
如果我們在 VElement 裏面也做個 assert,你就可以清楚的看到了。
因爲我們往下面傳,是沒問題的,但是首先,我自己得有這個 component,不然我都沒有,怎麼往下傳呢。
那這時候怎麼辦,我怎麼樣才能給它加上呢?其實特別的簡單。
大家別忘了,我們的 VComponent 是哪來的?是不是繼承自 VElement 的:
並且,在這個 VComponent 裏面,它的 super 這裏,我們要先搞清楚一個問題,在這,誰是組件?
比如現在,我想調父級,這裏的 super 對應的是不是就是 VElement?
那誰是組件?
其實就是我自己,VComponent 它自己就是組件。
那麼在這種情況下,我們就可以這麼來寫。
但是,你仍然可以看到頁面上的報錯:
它說,你在調用 super 之前,不能用 this,這就是一個雞生蛋還是蛋生雞的問題。
所以,現在這裏不能放 this,因爲這個時候,super 還沒執行完:
但是我創建的時候,確實又需要 this,那怎麼辦呢?
其實我們可以用一個特別簡單的辦法來解決這個問題。
現在只有一種人,是無須提供 component,就能直接用的,這種人是誰?
這種人是誰?就是我自己,我自己就是 component。
所以我們 VElement 這裏就不做 assert 了,因爲我自己,我這個VElement,有可能就是一個 component:
那我怎麼知道我是不是 component?
很簡單,那就得看看,是不是繼承出來的。
然後這個 component 有可能是空的,那如果是空的,我就用 this,因爲我是一個 component:
那麼你可以看到,這個時候,頁面上就沒有報錯了:
所以我們這個 component 的引用就算是好了。
然後我們把 cmp 打印出來看看,看看它的子級:
你可以看到,第一個子級是個 VElement,並且,它裏面有一個組件 _component。
這個組件是誰?你可以看到,就是我的父級,div#root。
包括下面的 VText 和 VElement,它們的 _component 也都是 div#root:
所以相當於現在,我是在用我未來的值,有點類似於高階類。
實際上來說,我自己有可能是個 VComponent,那我就用自己就好了。
當然,如果我提供了 component 就用,沒提供就用我自己,說明我自己就是頂層。
因爲我自己是沒有父級的,就這麼簡單。
這個東西稍微有點繞,首先,我們的最外層就是一個 VComponent,因爲我們寫的就是 let cmp = new VComponent({...})。
其實說白了,所有人引的都是最外層的它。
當然這個所有人,也包括它自己,它自己的 component 引用,就是它自己。
那爲什麼會有這樣的一個狀態呢?很簡單。
你別看我是 VComponent,沒錯,確實有點特殊,但我也是一個 VElement,因爲 VComponent extends VElement。
就是說,首先我是一個 VElement,然後其次我纔是一個 VComponent。
所以這裏面稍微有一點容易亂的地方就在於:不光最外層它裏面的那些東西 VElement、VText,它們都需要引我,這個大家肯定能理解,還有一點就是,我自己也要引我自己。
說的直白一點,我們寫的 let cmp = new VComponent({...}) 的這個 VComponent,它對應的其實就是最外層的 div:
根節點對應着根組件,很正常。
所以在這裏面有一個問題,就是我自己的父級,就是我自己,因爲已經到頭了。
所以,除了我下面的那些子元素得找我,因爲它們自己沒有數據,我有,所以它們肯定得找我。
然後除了它們找我之外,我自己也要找我自己。
因爲我自己,也就是最外層的這個根元素,也需要一些數據,比如像這些:
我也是需要數據的,這沒辦法。
所以在這種情況下,這個 component,它有可能有值:
爲什麼可能有值呢?
因爲我們在 createChildren 的時候,會傳一個 component:
我們有可能傳值了,也有可能沒傳值。
所以在下面,理論上我們就可以做一個判斷,如果 component 是有值的,那麼 this._component 就是 component:
這個相信大家絕對能理解,但是不太好理解的就是 else。
else 如果沒有值,說明我就是頂層,所以纔沒人給我。
所以在這時候,既然我就是頂級,那我就可以斷定,我自己是個 VComponent。
我們可以來試試,在 else 裏面我們來 console 一下:
這個時候,你可以看到,就是 true。
當然,在別的級別裏面,比如 VElement 和 VText,如果我們也 console 的話,看看它們是不是 VComponent:
你可以看到,都是 false,就我一個人是 true。
所以說白了,有一個元素是很特殊的,就是最外層的那個元素 div#root。
那麼它特殊在哪?特殊在它沒有父級,它自己就是那個根,這就意味着它就有兩重身份,它既是一個 VElement 標籤元素,同時它也是一個 VComponent 組件。
當然,爲什麼它是個 VComponent 組件,因爲我們在裏面的 super 會執行到 VElement 那去。
所以說白了,我們在 VElement 這裏就要判斷一下,有人給我傳,那挺好。
沒人給我傳怎麼辦?那我就要自己解決。
所以在 else 的時候,我的 _component,就是我自己:
當然,把它作一個簡寫,就是下面的這個東西:
相信大家現在就能理解了。
那麼接下來,我們在 VText 的編譯過程當中,其實就已經不光是有這個 s 了,並且還有數據了。
那麼這個數據從哪拿?就是從 this._component 裏面的 _data:
那麼現在這時候你可以看到,比如第一個 a,當我要編譯 a 的時候,是不是後面的數據就已經給我了呀,下面也都是一樣。
既然有了數據,那麼我們是不是就可以通過 this._component._data[s] 來做?當然這樣是沒有辦法適應表達式的,但沒關係,我們知道怎麼做就行,一步步來。
然後我們是不是應該把 this._component._data[s] 這個值給存起來,並且讓它拿去替換掉它原來的那個頁面裏的那堆東西。
以前的博客中,我們是用 replace 做的,而現在我們沒用 replace,所以這個工作我們就需要自己來。
當然這又是另一個工作了,這些其他的部分,怎麼給它擰出來,也是需要去做的。
所以目前來說,後面就都是一些勞動量的問題了,最主要的問題,我們已經解決完了。