function start(tagName, attrs) { let element = createASTElement(tagName, attrs); if (!root) { root = element; } currentParent = element; stack.push(element); }
function chars(text) { currentParent.children.push({ type: 3, text }) }
function end(tagName) { const element = stack[stack.length - 1]; stack.length--; currentParent = stack[stack.length - 1]; if (currentParent) { element.parent = currentParent; currentParent.children.push(element) } }
function parseHTML(html) { while (html) { let textEnd = html.indexOf('<'); if (textEnd == 0) { const startTagMatch = parseStartTag(); if (startTagMatch) { start(startTagMatch.tagName, startTagMatch.attrs); continue; } const endTagMatch = html.match(endTag); if (endTagMatch) { advance(endTagMatch[0].length); end(endTagMatch[1]) } } let text; if (textEnd >= 0) { text = html.substring(0, textEnd) } if (text) { advance(text.length); chars(text); } }
function advance(n) { html = html.substring(n); }
function parseStartTag() { const start = html.match(startTagOpen); if (start) { const match = { tagName: start[1], attrs: [] } advance(start[0].length); let attr, end while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) { advance(attr[0].length); match.attrs.push({ name: attr[1], value: attr[3] }) } if (end) { advance(end[0].length); return match } } } } // 生成语法树 parseHTML(`<div id="container"><p>hello<span>zf</span></p></div>`);
function gen(node) { if (node.type == 1) { return generate(node); } else { return `_v(${JSON.stringify(node.text)})` } }
function genChildren(el) { const children = el.children; if (el.children) { return `[${children.map(c=>gen(c)).join(',')}]` } else { return false; } }
function genProps(attrs) { let str = ''; for (let i = 0; i < attrs.length; i++) { let attr = attrs[i]; str += `${attr.name}:${attr.value},`; } return `{attrs:{${str.slice(0,-1)}}}` }
function generate(el) { let children = genChildren(el); let code = `_c('${el.tag}'${el.attrs.length?`,${genProps(el.attrs)}`:''}${children? `,${children}`:''})`; return code; } // 根据语法树生成新的代码 let code = generate(root); let render = `with(this){return ${code}}`; // 包装成函数 let renderFn = new Function(render); console.log(renderFn.toString());