[TOC]
* * * * *
## 1 源代碼文件
### 1-1 指令注冊
~~~
src\seed\lang.share.js
directive: function (name, definition) {
return this.directives[name] = definition
}
~~~
### 1-2 指令實現
~~~
src\directives\
~~~
## 2 流程分析
### 2-1 指令注冊
~~~
src\seed\lang.share.js
directive: function (name, definition) {
return this.directives[name] = definition
}
~~~
> name:指令的名稱
> definition:指令的配置信息
將指令以name為鍵,definition為值對應存儲到this.directives數組
###2-2 指令實現入口
~~~
src\directives\modern.js
require('./controller')
//處理屬性樣式
require('./attr.modern')
require('./css')
require('./visible')
//處理內容
require('./expr')
require('./text')
require('./html')
//需要用到事件的
require('./class.hover.active')
require('./on')
require('./duplex/modern')
//處理邏輯
require('./if')
require('./for')
require('./widget')
~~~
> 加載各個具體指令實現文件
### 2-3 指令實現舉例
~~~
src\directives\if.js
avalon.directive('if', {
priority: 5,
parse: function (binding, num) {
return 'vnode' + num + '.props["ms-if"] = ' + avalon.quote(binding.expr) + ';\n'
},
diff: function (cur, pre) {
if (cur.type !== pre.type) {
var list = cur.change || (cur.change = [])
avalon.Array.ensure(list, this.update)
}
},
update: function (dom, vnode, parent) {
var dtype = dom.nodeName.toLowerCase()
var vtype = vnode.type
if (dtype !== vtype) {
if (dom.nodeType === 1) {
avalon.caches[vnode.nodeValue] = dom
parent.replaceChild(avalon.vdomAdaptor(vnode).toDOM(), dom)
} else {
var s = dom.signature || dom.nodeValue
var keep = avalon.caches[s]
if (keep) {
parent.replaceChild(keep, dom)
patch([keep], [vnode])
} else {
var el = avalon.vdomAdaptor(vnode).toDOM()
parent.replaceChild(el, dom)
avalon.caches[s] = el
}
}
}
}
})
~~~
> 調用avalon.directive()注冊指令到全局指令數組
> 指令的配置信息包括
> > priority:指令優先級
> > parse:指令解析方法
> > diff:虛擬dom指令處理方法
> > update:虛擬dom指令刷新方法
## 3 if指令分析
~~~
avalon.directive('if', {
priotity:
parse:
diff:
update:
}}
~~~
> 注冊if指令到全局指令數組 avalon.directives
~~~
priority: 5,
~~~
> if指令優先級為5 指令的綁定解析排序時使用
~~~
parse: function (binding, num) {
return 'vnode' + num + '.props["ms-if"] = ' + avalon.quote(binding.expr) + ';\n'
},
~~~
> if指令的解析方法 指令的解析過程使用
返回字符串 `vnode1111.props["ms-if"]="binding.expr";`
~~~
diff: function (cur, pre) {
if (cur.type !== pre.type) {
var list = cur.change || (cur.change = [])
avalon.Array.ensure(list, this.update)
}
},
~~~
> if指令的比較方法 虛擬dom比較中if指令比較使用
> 判斷虛擬節點類型為if后,獲取當前if節點變化節點,
> 將變化節點的更新方法注冊為this.update
~~~
update: function (dom, vnode, parent) {
var dtype = dom.nodeName.toLowerCase()
var vtype = vnode.type
if (dtype !== vtype) {
if (dom.nodeType === 1) {
avalon.caches[vnode.nodeValue] = dom
parent.replaceChild(avalon.vdomAdaptor(vnode).toDOM(), dom)
} else {
var s = dom.signature || dom.nodeValue
var keep = avalon.caches[s]
if (keep) {
parent.replaceChild(keep, dom)
patch([keep], [vnode])
} else {
var el = avalon.vdomAdaptor(vnode).toDOM()
parent.replaceChild(el, dom)
avalon.caches[s] = el
}
}
}
}
~~~
> if指令的更新方法 在視圖同步刷新過程中使用
> 獲取dom節點名稱與虛擬dom節點類型
> 比較節點類型,調用對應虛擬dom節點的toDOM存儲
## 4 總結
### 4-1 意義
指令是mvvm的v層核心,可以看做瀏覽器運行的動態語言
### 4-2 思路
指令的實現通過avalon.directive(name,definition)
注冊到全局指令數組avalon.directives中
### 4-3 指令配置的調用過程(指令核心思想)
#### 指令priority的使用
~~~
src\strategy\parser\parseBindings.js
function parseBindings(props, num, elem) {
......
if (!bindings.length) {
ret += '\tvnode' + num + '.skipAttrs = true\n'
} else {
avalon.parseExpr(binding)
bindings.sort(byPriority).forEach(function (binding) {
ret += directives[binding.type].parse(binding, num, elem)
})
}
......
}
function byPriority(a, b) {
return a.priority - b.priority
}
~~~
>[info] parseBindings()調用bindigs.sort()按照優先級排序各個指令
#### 指令parse的使用
>[info] for指令解析
~~~
src\strategy\parser\parseView.js
str += avalon.directives['for'].parse(nodeValue, num)
~~~
>[info] widget指令解析
~~~
src\strategy\parser\parseView.js
if (hasWidget) {
str += avalon.directives.widget.parse({
expr: hasWidget,
type: 'widget'
}, num, el)
hasWidget = false
}
~~~
>[info] 其他指令的解析
~~~
src\strategy\parser\parseBindings.js
var hasBindings = parseBindings(el.props, num, el)
if (hasBindings) {
str += hasBindings
}
~~~
~~~
src\strategy\parser\parseView.js
function parseBindings(props, num, elem) {
......
if (!bindings.length) {
ret += '\tvnode' + num + '.skipAttrs = true\n'
} else {
avalon.parseExpr(binding)
bindings.sort(byPriority).forEach(function (binding) {
ret += directives[binding.type].parse(binding, num, elem)
})
}
.....
}
~~~
#### 指令的diff使用
~~~
src\strategy\diff.js
function diff(current, previous) {
......
case '#text':
if (!cur.skipContent) {
// 調用表達式比較
directives.expr.diff(cur, pre)
}
case '#comment':
if (cur.directive === 'for') {
// 調用for指令比較
i = directives['for'].diff(current, previous, i)
} else if (cur.directive ) {
// 調用if widget指令比較
directives[cur.directive].diff(cur, pre)
}
break
default:
if (!cur.skipAttrs) {
// 屬性比較
diffProps(cur, pre)
}
if (!cur.skipContent) {
// 遞歸比較子節點
diff(cur.children, pre.children || emptyArr)
}
break
......
}
~~~
~~~
src\strategy\diff.js
function diffProps(current, previous) {
for (var name in current.props) {
var match = name.match(rbinding)
if (match) {
var type = match[1]
try {
if (directives[type]) {
directives[type].diff(current, previous || emptyObj, type, name)
}
} catch (e) {
avalon.log(current, previous, e, 'diffProps error')
}
}
}
}
~~~
>[info] 調用指令的diff比較虛擬dom
#### 指令的update使用
- 概述
- 框架目錄
- 組件目錄(components\)
- 生成目錄(dist\)
- 測試目錄(karma\)
- 示例目錄(perf\)
- 主體目錄(src)
- 其他文件
- 框架流程
- 前:章節說明
- 主:模板掃描(avalon.scan())
- 主:VM創建(avalon.define())
- 主:同步刷新(avalon.batch())
- 附:節點解析(avalon.lexer())
- 附:虛擬DOM(avalon.vdomAdaptor())
- 附:渲染函數(avalon.render())
- 附:VM生成(avalon.masterFactory())
- 附:節點diff(avalon.diff())
- 主:界面事件(test)
- 框架工具
- 另:全局函數
- 另:全局正則
- 另:事件接口
- 另:組件接口
- 另:DOMApi
- 框架驅動
- D : 指令實現
- D:兼容處理
- 使用范例
- 基礎原理
- js模塊
- js對象
- js函數
- js數組
- js字符串
- dom接口
- 框架心得
- 心:總體思路