書接上回,我們要接著往/src/ast/parse.ts的parse方法的方法體內寫東西。
來明確一下我們首先需要甚麼吧。遍歷嘛,指針是需要的;需要先把上標籤挑出來,所以檢測上標籤的正則也是需要的;同理,也需要檢測下標籤的正則;最後就是檢測內文的正則。
templateString = templateString.trim()
// 指針
let index = 0
// 檢測開始標籤,捕獲標籤內文字。ex:<(div)>
const startRegExp = /^\<([a-z]+[1-6]?)(\s[^\<]+)?\>/
// 檢測結束標籤,捕獲標籤內文字。ex:</(div)>
const endRegExp = /^\<\/([a-z]+[1-6]?)\>/
// 檢測文字+下標籤
const wordRegExp = /^([^\<]+)\<\/[a-z]+[1-6]?\>/
實際上上標籤的水很深,要完美匹配template中可能出現的所有上標籤,這個正則是絕對不夠用的。但還記得我們這次鐵人賽的標題嗎?我們淺談,水深的不碰(?)
一方面這水太深我也把持不住,另一方面最近太多想學習的技術積著了,時間不夠也是問題……要是真對怎麼完美匹配上標籤感興趣,請直接去翻源碼吧,恕我就只淺談了。
回歸正題,因為html標籤屬於是嵌套關係,一個套一個,先有父標籤,再有子標籤,子標籤先閉合,父標籤才閉合。先有後閉,先進後出,正所謂棧結構。
所以我們再開一個棧來裝遍歷到的標籤:
const tagStack: string[] = [];
type TagContent = {
tag?: string;
attrs?: Record<string, any>;
children: (string | TagContent)[];
};
const textStack: TagContent[] = [{ children: [] }];
之後每當有標籤入棧tagStack,就給textStack入棧一個TagContent型別的對象,來裝之後我們解析出來的標籤名、屬性及內容。因為把template全部解析完以後還需要有一個對象來裝著,所以textStack默認有包含children屬性的第0項,之後textStack會維持比tagStack多一項,除去textStack的第0項以外的每一項,都和tagStack的每一項一一對應。
就是這種關係:
所以接下來我們的步驟是這樣的:
循環上述步驟直到遍歷完整個template以後,我們就能得到類似這種結構的樹:
{
children: [
{
tag: 'h1',
props: {},
children: ['願望清單']
},
{
tag: 'ul',
props: { style: 'list-style: none;' },
children: [
{
tag: 'li',
props: {},
children: '漲薪'
},
{
tag: 'li',
props: {},
children: '準時下班'
},
{
tag: 'li',
props: {},
children: '再和昨天提到的學姊當一回同事'
}
]
}
]
}
如何,是不是很像昨天提到的h函數可以接收的參數?只要把template解析成樹結構,接下來就只要遞歸調用h函數,虛擬dom就大功告成。
而這就是我們明天的課題了。
github - [Day 24]ast抽象語法樹 - 2——前置準備及明確目標