剛剛已經(jīng)看完了作者 yyx 的第一次嘗試,作者可能發(fā)現(xiàn),唉,好像這種方法行得通,然后在 src 下寫了一個功能相對更多的代碼實現(xiàn)
里面的 dev.html 則是運行 src 代碼的 example
由于我折騰了好久也沒能將 grunt 跑明白,為了節(jié)約時間,決定將代碼拷出來,用 rollup 去打包,自己跑一個
將 require 語法改成 import


導(dǎo)出的地方也用 es 的語法進(jìn)行導(dǎo)出
demo 地址在這里
然后我們來調(diào)試這個代碼,看一看這個功能相對多一點的是怎么實現(xiàn)的
老規(guī)矩,先看函數(shù)的調(diào)用方式

可以看到,引入 Seed(一個自定義名稱的對象) 對象,調(diào)用了 Seed.create ,傳入對象作為參數(shù),兩個變量 msg 和 hello ,還有一個方法 changeMessage

可以看到,導(dǎo)出的 create 函數(shù)就是 main.js 中的 Seed 構(gòu)造函數(shù)

然后開始拆解這個構(gòu)造函數(shù),看一看 new 的過程干了什么
可以看到,和上一篇文章執(zhí)行的是同一個套路,self 指向自身,獲取傳入 id 的 dom 下的自定義在標(biāo)簽上的 NodeList , 然后初始化自身的作用域 scope

上圖同樣的遍歷對象,從函數(shù)名可知,此流程是 遍歷 els -> 處理 Node 節(jié)點 -> 克隆節(jié)點上的自定義屬性 -> 遍歷這些屬性 -> 解析指令 -> 如果解析成功,將指令綁定
下面就是一段給 self.scope 賦值,和上一篇文章一樣,賦值觸發(fā)對象的 set , 然后進(jìn)行響應(yīng)式更新
來先看第一個函數(shù)


可以看到,遍歷節(jié)點的屬性,將屬性名和對應(yīng)的值返回一個對象數(shù)組

處理 attr key
遍歷此數(shù)組的每一項去嘗試解析指令,看看 vue 提供的語法和用戶傳入的用法是否能對應(yīng)的上

此時的 attr 是這種形式的
var attr = {
"name": "sd-text",
"value": "msg | capitalize"
}

函數(shù)返回前,處理了一系列的邏輯,首先判斷了是 sd 開頭的指令才向下執(zhí)行,noprefix 記錄了沒有前綴的指令名,下文拿 sd-text="msg | capitalize" 舉例:

首先,裁剪掉指令前面的 sd- 前綴,留下純凈的指令信息,再去嘗試獲取 argIndex 的位置
argIndex = noprefix.indexOf('-')
這里是為了判斷 sd-on-click="changeMessage | .button" 這種情況,有兩個 -
如下圖

對不同的指令進(jìn)行不同的處理,以獲取到對應(yīng)的 dirname , 如果是普通指令返回諸如 text 這種,如果是事件監(jiān)聽,返回 dirname 為 on
之后去獲取 directives.js 文件下對應(yīng) dirname 作為 key 的值

處理 attr value
代碼如下

判斷有無管道符號 ?裁剪管道符前面的變量賦值給 key : 直接將 attr.value 賦值給 key


以上是有無管道符號處理 value 值的區(qū)別
處理完成后,將后續(xù)所有管道符號進(jìn)行處理,返回一個 filters 數(shù)組

處理完 attr.key attr.value 之后,函數(shù)返回,返回了一個對象,在 update 屬性中,區(qū)分了一下是事件監(jiān)聽,還是普通的指令

進(jìn)行綁定

下圖是參數(shù)

el.removeAttribute(directive.attr.name)
此函數(shù)執(zhí)行了移除標(biāo)簽上的自定義屬性,取指令綁定的值對應(yīng)的變量也就是 key 屬性對應(yīng)的 msg
if (!binding) {
bindings[key] = binding = {
value: undefined,
directives: []
}
}
嘗試直接從 bindings 中獲取值,但是我們的 bindings 初始化的時候是一個空值,所以函數(shù)會進(jìn)入 if (!binding) 這段邏輯
directive.el = el
binding.directives.push(directive)
給 bindings 對象進(jìn)行賦值 -> 在 directive 上添加 el 屬性,指向綁定的 dom -> 將 directive 直接推送到剛剛 bindings[key] 賦值的新對象的 directives 里面,因為 binding 和 bindings[key] 是引用關(guān)系,所以面直接向 directives 添加對應(yīng)的指令信息
if (directive.bind) {
directive.bind(el, binding.value)
}
上面的分析可知,我們每一個 directive 是沒有 bind 屬性的所以這段邏輯不會執(zhí)行
if (!seed.scope.hasOwnProperty(key)) {
bindAccessors(seed, key, binding)
}
判斷 scope 是否還沒有對應(yīng)綁定的屬性(也就是綁定的 key 還沒有被 Object.defineProperty 定義對應(yīng)的 get set),執(zhí)行 bindAccessors 函數(shù)

拿剛剛的綁定的 msg 舉例,當(dāng)給 scope.msg 賦值的時候,會觸發(fā) set 邏輯,下面是此函數(shù)的參數(shù)

首先先給指令上綁定的 value 賦值,后面判斷如果 value 存在,嘗試執(zhí)行 filter 邏輯

因為我們沒有定義 customFilter 所以執(zhí)行 else , 在 Filters.js 文件下

去獲取定義好的函數(shù),將傳進(jìn)來的 hello 字符串首字母變成大寫,然后將處理完成的值 return
directive.update(
directive.el,
value,
directive.argument,
directive,
seed
);
});
最后執(zhí)行了指令定義的 update,看函數(shù)傳參,我們有 dom ,value ,directive 下的參數(shù),directive 本身,seed 實例本身,也就是說,所有的數(shù)據(jù)都有了,update 也早就定義好了對應(yīng)的行為,那么此函數(shù)調(diào)用的時候,便會執(zhí)行,對應(yīng)的邏輯,這些邏輯都是簡單的操作 dom , 就不再贅述了

好了,這也就是 vue 0.1 版本做到的,運行時 + 指令 + 響應(yīng)式 的一個實現(xiàn)了
本文使用 文章同步助手 同步