[TOC]
* * * * *
## 1 源代碼文件
### 1-1渲染入口
~~~
src\strategy\index.js
~~~
### 1-2 渲染實現
~~~
src\strategy\parser\parseView.js
~~~
## 2 流程分析
### 2-1 渲染調用
~~~
src\dom\ready\scan.js
vm.$render = avalon.render(vtree)
~~~
> 調用avalon.render()
將虛擬dom樹生成渲染函數vm.$render
### 2-2 渲染入口
~~~
src\strategy\index.js
function render(vtree) {
var num = num || String(new Date - 0).slice(0, 6)
var body = parseView(vtree, num) + '\n\nreturn vnodes' + num
var fn = Function('__vmodel__', body)
return fn
}
avalon.render = render
~~~
> vtree: avalon.lexer()解析生成的虛擬dom樹
> 首先獲取當前日期num
> 調用parseView(vtree,num)生成函數主體
> 調用Function()生成渲染函數
Function()見 基礎原理的js對象
### 2-3 渲染函數生成
~~~
src\strategy\parser\parserView.js
function parseView(arr, num) {
num = num || String(new Date - 0).slice(0, 5)
var forstack = []
var hasIf = false
var children = 'vnodes' + num
var vnode = 'vnode' + num
// 節點數組聲明 var vnodes11111=[]
var str = 'var ' + children + ' = []\n'
for (var i = 0; i < arr.length; i++) {
// 當前解析階段
var el = arr[i]
// 虛擬文本節點
if (el.type === '#text') {
// 函數語句 var vnode1111 = {type:"#test",skipContent:true}
str += 'var ' + vnode + ' = {type:"#text", skipContent:true}\n'
// 檢查是否包含{{}}的定界符
var hasDelimiter = rexpr.test(el.nodeValue)
if (hasDelimiter) {
// 存在定界符,解析定界符內容
var array = parseDelimiter(el.nodeValue)
// 返回的字符串棧
if (array.length === 1) {
// 單個界定符內容
var a = parseExpr(array[0].expr)
// vnode1111.nodeValue=結果
str += vnode + '.nodeValue = ' + wrapDelimiter(array[0].expr) + '\n'
} else {
// 多個界定符
a = array.map(function (el) {
return el.type ? wrapDelimiter(el.expr) : quote(el.expr)
}).join(' + ')
// vnode1111.nodeValue = String()
str += vnode + '.nodeValue = String(' + a + ')\n'
}
// vonde1111.fixIESkip = true
str += vnode + '.fixIESkip = true\n'
// vonde1111.skipContent = false
str += vnode + '.skipContent = false\n'
} else {
// 不存在界定符
if (rsp.test(el.nodeValue)) {
// vnode1111.nodeValue = " "
str += vnode + '.nodeValue = "\\n"\n'
} else {
// vnode1111.nodeValue = ' ';
str += vnode + '.nodeValue = ' + quote(el.nodeValue) + '\n'
}
}
// vnodes.push(vnode);
str += children + '.push(' + vnode + ')\n'
// 虛擬注釋節點
} else if (el.type === '#comment') {
var nodeValue = el.nodeValue
// ms-for:注釋性指令
if (nodeValue.indexOf('ms-for:') === 0) {
var signature = el.signature
// for棧存儲
forstack.push(signature)
/*var $for = {
type:"#comment",
directive:"for",
skipContent:false,
signature:"$for",
start:childenr.length,
nodevalue:nodeValue;
}*/
str += '\nvar ' + signature + '= {' +
'\n\ttype:"#comment",' +
'\n\tdirective:"for",' +
'\n\tskipContent:false,' +
'\n\tsignature:' + quote(signature) + ',' +
'\n\tstart:' + children + '.length,' +
'\n\tnodeValue:' + quote(nodeValue) +
'\n}\n'
// 節點壓棧 vnodes1111.push()
str += children + '.push(' + signature + ')\n'
// 調用for指令進行解析
str += avalon.directives['for'].parse(nodeValue, num)
// ms-for-end:注釋性指令
} else if (nodeValue.indexOf('ms-for-end:') === 0) {
var signature = forstack[forstack.length - 1]
str += children + '.push({' +
'\n\ttype:"#comment",' +
'\n\tskipContent:true,' +
'\n\tnodeValue:' + quote(signature) + ',' +
'\n\tkey:traceKey\n})\n'
str += '\n})\n' //結束循環
if (forstack.length) {
var signature = forstack[forstack.length - 1]
str += signature + '.end =' + children + '.push({' +
'\n\ttype:"#comment",' +
'\n\tskipContent:true,' +
'\n\tsignature:' + quote(signature) + ',' +
'\n\tnodeValue:' + quote(signature + ':end') +
'\n})\n'
forstack.pop()
}
//插入普通JS代碼
} else if (nodeValue.indexOf('ms-js:') === 0) {
str += parseExpr(nodeValue.replace('ms-js:', ''), 'js') + '\n'
//其他文本值
} else {
str += children + '.push(' + quote(el) + ')\n\n\n'
}
continue
// 虛擬元素節點
} else {
// ms-if指令處理
var hasIf = el.props['ms-if']
if (hasIf) { //?處理ms-if指令
el.signature = makeHashCode('ms-if')
str += 'if(!(' + parseExpr(hasIf, 'if') + ')){\n'
str += children + '.push({' +
'\n\ttype: "#comment",' +
'\n\tdirective: "if",' +
'\n\tnodeValue:' + quote(el.signature) + ',\n' +
'\n\tsignature:' + quote(el.signature) + ',\n' +
'\n\tprops: {"ms-if":true} })\n'
str += '\n}else{\n\n'
}
str += 'var ' + vnode + ' = {' +
'\n\ttype: ' + quote(el.type) + ',' +
'\n\tprops: {},' +
'\n\tchildren: [],' +
'\n\tisVoidTag: ' + !!el.isVoidTag + ',' +
'\n\ttemplate: ""}\n'
//ms-widget指令
var hasWidget = el.props['ms-widget']
if (hasWidget) {//?處理ms-widget指令
str += avalon.directives.widget.parse({
expr: hasWidget,
type: 'widget'
}, num, el)
hasWidget = false
} else {
var hasBindings = parseBindings(el.props, num, el)
if (hasBindings) {
str += hasBindings
}
if(el.children.length){
str += vnode + '.children = ' + wrap(parseView(el.children, num), num) + '\n'
}else{
str += vnode + '.template = ' + quote(el.template) + '\n'
}
}
str += children + '.push(' + vnode + ')\n'
if (hasIf) {
str += '}\n'
hasIf = false
}
}
}
return str
}
~~~
>[info] 1 虛擬文本節點渲染
~~~
if (el.type === '#text') {}
~~~
> 檢查界定符{{}},
> 存在解析{{}}插值表達式
> 不存在直接保存
* * * * *
>[info] 2 虛擬注釋節點渲染
~~~
else if (el.type === '#comment') {}
~~~
> ms-for:類注釋解析
> ms-for-end:類注釋解析
> ms-js:普通js代碼解析
* * * * *
>[info] 3 虛擬元素節點渲染
~~~
else { }
~~~
> ms-if 指令處理
> ms-widget 指令處理
## 3 其他操作
## 4 總結
### 4-1 意義
解析虛擬dom樹vtree,生成對應渲染函數
### 4-2 思路
主要包含三種虛擬節點的解析與生成
文本虛擬節點,注釋虛擬節點,元素虛擬節點
### 4-3 參考
- 概述
- 框架目錄
- 組件目錄(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接口
- 框架心得
- 心:總體思路