多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[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 参考