iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
Vue.js

淺談vue3源碼,很淺的那種系列 第 28

[Day 27]ast抽象語法樹 - 4——解析屬性

  • 分享至 

  • xImage
  •  

為了解析上標籤中的屬性,我們新建/src/ast/parseAttr.ts文件,並寫下以下代碼:

export default (attrsString: string) => {
  const result = {};
  if (!attrsString) return result;
};

這個方法接收的attrsString來自上標籤扣掉標籤名以外的部分,比方說可能會是這種格式:

class="ccc" style="color: pink;" href="https://www.youtube.com/channel/UCEQfDopfJepHUrdirQw5wlw"

我們可以從中看出一些規律:

  1. 可以空格分隔
  2. 雙引號與雙引號之間的內容是屬性的值**(可能出現空格!)**

再次強調,雙引號與雙引號之間的屬性的值是有可能出現空格的,因此沒辦法直接用split(' ')區隔屬性。我們需要遍歷這個屬性字串,挑出雙引號外的所有空格,以這些雙引號外的空格為準區分所有屬性。

因此解析屬性有三個關鍵:

  1. 遍歷
  2. 目前遍歷到的字是否在雙引號之間
  3. 目前遍歷到的字是否為空格

說起遍歷,首先我們需要一個指針。然後我們還需要一個變數,來記錄目前遍歷到的字是否處在雙引號之間。

let inQuotation = false;
let point = 0;

然後就是慣例的遍歷了。

// 遍歷各標籤屬性,依序將其整理成物件形式
for (let i = 0; i < attrsString.length; i++) {
  const char = attrsString[i]
  if (char === '"') inQuotation = !inQuotation
  else if (char === ' ' && !inQuotation) {
    Object.assign(result, generateAttr(attrsString.substring(point, i)))
    point = i
  }
}
Object.assign(result, generateAttr(attrsString.substring(point)))

return result

只要看到雙引號",就切換inQuotation;只要是在!inQuotation的情況下看到空格,就代表我們剛看完一個屬性,這時就取出point到i之間的內容,之後會寫一個generateAttr函數來把這段內容加工成一個對象。把剛遍歷到的屬性家工成對象後併入result,遍歷完整段屬性字串後將result返回,就是我們要的屬性對象了。

我們再接著寫能把單一屬性字串加工成對象的generateAttr。

const generateAttr = (attrString: string) => {
  attrString = attrString.trim();
  if (attrString[0] === ':') attrString = parseAttrData(attrString);
  const attrArr = attrString.match(/^(.+)="(.+)"$/);
  const result: Record<string, any> = {};
  if (attrArr[1] === 'style') {
    result.style = parseStyles(attrArr[2]);
  } else result[attrArr[1]] = attrArr[2];

  return result;
};

generateAttr接收的參數attrString是單一屬性的字串,大部分的屬性,像是class或href,都只要把屬性的種類作為key,屬性的內容作為值,就能加工成一個代表屬性的對象,譬如class="some-class"可以直接變成{ class: 'some-class' },不需要額外做點甚麼,就是最單純的情況。

但如果是v-bind之後的屬性,例如:class或:style,就需要做一些額外處理;一般的style也需要做額外處理,因為我們在虛擬dom上期望的style也是一個對象,譬如{ style: { color: 'pink', border: '1px solid black' } }。

所以我們之後再寫一個parseAttrData來處理v-bind的屬性,以及parseStyles來處理style的情況。剩下的代碼就很單純,用正則表達式把()="()"括號內的東西拆開,組成對象即可。

如此一來我們便完成了解析屬性大部分的工作,明天我們會再著手進行v-bind及style的解析,完成最後的任務。

github - [Day 27]ast抽象語法樹 - 4——解析屬性


上一篇
[Day 26]ast抽象語法樹 - 3——解析文字
下一篇
[Day 28]ast抽象語法樹 - 5——v-bind與style
系列文
淺談vue3源碼,很淺的那種31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言