Open jiefancis opened 1 year ago
template解析成ast,如何确定ast的父子关系? stack栈的先入后出的特性,当遇到开始标签时入栈,遇到结束标签时出栈。dom树形结构具备这样的特性
template如何解析标签、属性、节点?
怎么匹配并解析非插值节点? html.indexOf('{{') === 0.,如果你的正则表达式掌握的还不错,可以尝试引入正则匹配。 if (html.match(/{{(.*)}}/)) { RegExp.$1} 获取插值表达式
var template = ` <div class="container" id="container"> <input type="text" v-model="a.b"></input> {{state}} <div class="h1"> <span>标题</span> {{title}} </div> </div> ` parse(template) function parse(template) { let root = null, stack = [], html = template, i = 0; return parseHTML() function parseHTML() { while(html) { // 开始 // 保证当前是 < 开头 html = html.trim() if(html.indexOf('<') === 0) { if(html.indexOf('</') === 0) { parseTagEnd() } else { parseTagStart() } } else if(html.indexOf('{{')===0) { console.log('匹配插值',html) // 文本节点中的插值节点 parseInterpolate() } else { parseStaticText() } } return root } // 处理静态文本节点 function parseStaticText(){ let end = html.indexOf('<'); let content = html.slice(0, end); html = html.slice(end) let staticNode = { type: 'text', text: content, isStatic: true, } if(stack.length) { stack[stack.length - 1].children.push(staticNode) } } // 找到插值,对象类型 a.b 如何处理? function parseInterpolate() { html = html.trim() let end = html.indexOf('}}') let content = html.slice(2, end) html = html.slice(end+2).trim() const textNode = { type: 'interpolate', text: content } console.log('插值节点', content) stack[stack.length - 1].children.push(textNode) } function parseTagStart() { html = html.trim() let end = html.indexOf('>'); console.log('起始标签', html) let content = html.slice(1,end).trim(); html = html.slice(end+1).trim() let space = content.indexOf(' '), tagName = ''; if(space === -1) { tagName = content content = '' } else { tagName = content.slice(0, space).trim() content = content.slice(space+1).trim() } console.log(html, space, 123456, tagName, 'starttttttt', content) let attrsMap = content ? parseAttrs(content) : {} let node = createVnode(tagName, attrsMap, []) if(!root) { console.log('start Node', root) root = node } stack.push(node) } function parseTagEnd() { // 处理>前面有空格的情况 html = html.slice(html.indexOf('>') + 1) processElement() } function parseAttrs(attrStr) { let list = attrStr.split(' ').map(attr => attr.trim()) let map = {} console.log(list,1234567890) list.forEach(attr => { let kv = attr.split('=') map[kv[0]] = kv[1].replace(/["']?/g, '') }) return map } function createVnode(tag, rawAttrs, children = []) { return { type: 'element', tag, rawAttrs, children } } function processElement() { let currentEle = stack.pop(), len = stack.length, topEle = stack[len-1]; currentEle.attrs = {} if(len) { const { tag, rawAttrs } = currentEle; let keys = Object.keys(rawAttrs) // 处理属性 keys.forEach(prop => { if(prop === 'v-model') { processVmodel(currentEle) } else if(prop.match(/^v-bind:(.*)/)) { processVbind(currentEle, RegExp.$1, rawAttrs[`v-bind:${RegExp.$1}`]) } else if(prop.match(/^v-on:(.*)/)) { processVon(currentEle,RegExp.$1, rawAttrs[`v-on:${RegExp.$1}`]) } }) topEle.children.push(currentEle) } } function processVmodel(ele) { const { tag, rawAttrs, attrs } = ele; const { type, 'v-model': vModelValue} = rawAttrs; // type = 'text' 'checkbox' 'gradio' if(tag === 'input') { attrs.vModel = { tag, type, value: vModelValue} } else if(type === 'textarea') { attrs.vModel = { tag, value: vModelValue} } else if(type === 'select') { attrs.vModel = { tag, value: vModelValue} } } function processVbind(ele, bindKey, bindValue) { ele.attrs.vBind = {[bindKey]: bindValue} } function processVon(ele, onKey, onValue) { ele.attrs.vOn = {[onKey]: onValue} } }
看完编译器,能明白以下问题
template解析成ast,如何确定ast的父子关系? stack栈的先入后出的特性,当遇到开始标签时入栈,遇到结束标签时出栈。dom树形结构具备这样的特性
template如何解析标签、属性、节点?
怎么匹配并解析非插值节点? html.indexOf('{{') === 0.,如果你的正则表达式掌握的还不错,可以尝试引入正则匹配。 if (html.match(/{{(.*)}}/)) { RegExp.$1} 获取插值表达式