JavaScript進階(二十六):DOM 的編譯(一)

經過前面的幾篇博客,相信到現在爲止,一些 DOM 的基本操作是沒問題的,那麼接下來就要做點事了,我們來嘗試着去編譯真實的 DOM 節點。

什麼叫編譯?很簡單。

第一,我要把這個真實存在的元素,變成一個我自己的虛擬 DOM 元素。

第二,我要把這個元素身上,跟我相關的東西,都拿出來。

 

假設現在以 vue 爲例,對於 vue 來說,你上面加個 title,人家關心嗎?

不關心。人家關心的,其實是跟我有關係的東西。

你比方說我加了個 v-if,或者 @click:

這個我關心。

說白了,就是我在編譯的過程當中,我要把跟我有關的,有功能的,這些自定義的屬性,給它拎出來,將來我要用。

那麼我們現在就直接來看一看,怎麼來編譯 DOM 節點。

當然,僅僅只算是一個初級版本,因爲這個事可大可小,它未來其實會有很多複雜的東西。

所以我們現在要做的是一個初級的版本,所以也不會特別難。

 

那麼現在,我希望是這樣的,比方說,我有一個姓名 name:

當然順便一說,我一定得用這個雙花括號 {{ }} 嗎?一定得跟着 vue 走嗎?

不一定,我可以用任何我想的東西,反正是我們自己寫的。

比方說,我就想用 % 間隔,行嗎?

隨便,愛用啥用啥。

只是雙花括號 {{ }} 我們用習慣了,所以暫時還是這個。

 

然後繼續,比方說,我還希望這裏面可以給我做一些簡單的運算:

這個要求也不復雜。

以及呢,我還希望這裏面可能有一些按鈕之類的東西,當我點擊這個按鈕的時候,這個 a 可以給我++

當然我們先一步一步的來,首先,我們想要來編譯這個元素:

那麼這個時候,第一件事,我們是不是要把它裏面,所有的這些,所謂的模版,我要把它給挑出來啊?

也就是說,我關心的是 {{ 開頭,}} 結尾,我關心的是這些東西。

 

那麼接下來,我們要怎麼做呢,我們一步一步來。

首先,你如果想把這個東西做的好一點,我們肯定是把它封成一個 class:

然後接下來呢,這裏面需要一個 options,而且默認的時候,讓它是一個空 json:

然後接下來先不管別的,我們先看看這裏面具體想幹點什麼。

別的可能還不是特別關心,至少,我得有個 render 吧:

那麼這個 render 具體怎麼做是重點,我們一步一步來。

 

首先,爲了寫起來方便,我們把 js 這塊單獨的拎走,不然寫起來太亂了。

這樣的話,我們可以左右對照,看起來也方便一些。

然後,我們這個東西,先不管裏面怎麼寫,我就想看看怎麼用。

比方說,我現在就來 new 一個,然後這裏面會有一些小小的參數,比如我有一個 root:

然後我們除了需要根元素以外,是不是還需要數據啊?

然後開始的第一個事,我希望可以有一個 assert,這個我們前面已經用過很多次了,熟的很。

那麼這個 assert 有了之後,我需要檢查很多東西。

首先,我們是不是需要根據 damu 所提供的 root 參數,來具體的把根元素給選出來啊。

那麼這時候,是不是就可以跟以前一樣,我們單獨搞一個小操作,比如 _getElement:

我要的很簡單,首先,我需要 assert 一下,參數 obj 你必須得有,沒有就報錯。

然後接下來,我們就來稍微的判斷一下,如果它是 string,我們就自己來選,並且還得在判斷一下,這東西有沒有。

而反過來,如果它是一個元素,是的話就直接用,如果還不是的話,我就報錯。

這個東西我們前面也寫了很多遍,太熟了,就直接來了:

現在已經有了_getElement,那麼我們就可以得到 _root 了:

然後這個有了之後,還沒完,我們還需要用一個特別重要的東西,就是我得讓 options.data 變成可響應的狀態。

正經的情況下,我們需要各種判斷,它是不是一個函數,怎麼怎麼着。

在這,我們就一切從簡,反正這些事,我們前面都做過,所以這裏就不再去重複了。

然後這個 data 已經有了,那麼剩下的事怎麼辦?

是不是就可以創建一個 proxy 對象,因爲我要監聽它裏面的東西:

這裏我們也可以直接把 options.data 給丟進去,合成一步。

然後接下來,我這裏面需要各種各樣的東西,比如 get 和 set:

再接下來呢,我們的 render 裏面是不是也要開始做事了啊?

到這裏爲止,你可以發現上面很多的操作都沒有細說,因爲我們前面做過很多次了,如果不是很懂,可以看下前面的博客。

 

那麼到現在,我現在這個 proxy 確實是有了,我們就來看看:

可以看到,我們的實例 damu 身上並沒有 a,爲什麼呀?原因非常簡單。

注意,我們在這要區分一個東西,proxy 和 this

我們在外面這麼去寫:damu.a

請問這時候,我們是從誰上面去拿 a 的?其實是從 this 身上去拿的。

那麼我們 this 身上有沒有 a 這個東西?並沒有。

誰身上有?是不是 proxy 身上有?那這時候怎麼辦呢?

我們能寫 this = proxy 嗎?這麼寫肯定報錯的:

那有沒有別的辦法呢?有。

在這我們就要說一個及其另類的方法。

 

比方說我有一個類:

可以看到,現在一切沒問題。

但是,在 js 裏面,有一個很變態的特性,就是 constructor 是可以有返回值的。

比如我現在返回一個 json:

那麼你可以看到,我現在得到的這個實例 a,就是這個 json。

換句話說,在其他語言裏面,比如 java,constructor 其實是不能有 return,不能有返回值的,它的返回值就是剛構造好的那個東西,不能是別的。

而 js 當中,它可以 return 一個東西,只要你願意,我 return 一個任意的對象都行,比如:

 

那麼回到正題,這時候,在外面我們希望設置數據的時候,能夠往 proxy 身上設。

所以,我們是不是就可以直接把 proxy 給 return 出去:

既然 return 了 proxy,那相當於我自己的 this 就廢了。

當然這時候有人可能會說,那你這 this 身上的 _root 和 timer 不也沒了嗎?

其實這個 this 其實還是存在的,比方說 set 裏面,我們依然調的是 this.render()。

所以說我的 this 並沒有消失,只不過我是推出去一個頂雷的:有設置數據的 proxy 去,你頂上。

 

那麼現在,我們來試試:

現在就可以看到,damu 上面是有 a 的了。

然後我們還想賦個值:

這時候就可以看到報錯了,爲什麼會報錯?

因爲在 set 裏面,this 指的就是 proxy。

所以我們需要稍微的變一變:

這時候,render 就出來了。

 

當然,這個並不是唯一的選擇,我們也可以搞一個箭頭函數:

可以看到,也是能出來的。

當然,我個人與其說把大量的函數都寫成這種箭頭函數,我更願意用 _this。

 

那麼到這爲止,我們已經能夠讓它正確的做出響應了。

但是別忘了,我們的 render 裏面到現在爲止,什麼都沒有。

所以,下篇博客我們就開始來幹這個事。

 

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