ast语法树变成render字符串

2021-08-19  本文已影响0人  JX灬君

ast语法树变成render字符串

  1. ast语法树变成字符串generate(ast)

    =>html元素:
    <div id='app' style="color:red">hello {{msg}}</div>

    =>转换成ast语法树:
    {"tag":"div","type":1,"children":[{"type":3,"text":"hello{{msg}}"}],"attrs":[{"name":"id","value":"app"},{"name":"style","value":"color:red"}],"parent":null}

    =>转换成render字符串:
    _c('div',{id:"app",style:{"color":"red"}},_v("hello"+_s(msg)))

    _c:处理标签 _v:处理文本 _s:处理{{}}

let code = generate(ast)
function generate(el) {
    // console.log(el)
    let children = genChildren(el)
    //方法 拼接字符串  源码也是这样操作 [{}]    ${el.attrs.length?`{style:{color:red}}`:'undefined'}
    let code = `_c('${el.tag}',${el.attrs.length ? `${genProps(el.attrs)}` : 'undefined'}${
        children ? `,${children}` : ''
        })`

    return code

}
  1. 处理属性

    // 处理元素的属性
    function genProps(attrs) {
        //处理属性
        let str = ''
        for (let i = 0; i < attrs.length; i++) {
            let attr = attrs[i]
            //注意;   style:"color:red;font-size: 20px
            if (attr.name === 'style') {
                let obj = {} //对样式进行特殊处理
                attr.value.split(';').forEach(item => {
                    let [key, value] = item.split(':')
                    obj[key] = value
                })
                attr.value = obj //
            }
            //其他  'id:app',注意最后会多个属性化 逗号
            str += `${attr.name}:${JSON.stringify(attr.value)},`
        }
        return `{${str.slice(0, -1)}}`  // -1为最后一个字符串的位置  演示一下 
        // let reg =/a/g    reg.test('ad') false  
    }
    
  1. 处理子节点genChildren()方法(1)

    //判断是否有儿子
    function genChildren(el) {
        const children = el.children
        if (children) { //将所有
            return children.map(child => gen(child)).join(',')
        }
    
    
    }
    
    
  2. 处理子节点gen()方法(2)

    判断{{}}的正则const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g // {{xx}} 默认的 双大括号

    正则表达式通过exec返回匹配到的内容

ex: let res = /a/g res.exec('abc') 结果: ["a", index: 0, input: "abc", groups: undefined]

// 类型:1:元素div 3:文本
function gen(node) { //获取到的元素
    //注意 是什么类型    1.div 3.文本
    if (node.type === 1) {
        return generate(node) //生成元素节点的字符串
    } else {
        let text = node.text // 获取文本  注意  普通的文本  hello{{name}}?{{num}}
        if (!defaultTagRE.test(text)) {
            return `_v(${JSON.stringify(text)})`  // _v(html)  _v('hello'+_s(name))
        }
        let tokens = [] //存放每一段的代码
        let lastIndex = defaultTagRE.lastIndex = 0;//如果正则是全局模式 需要每次使用前变为0
        let match;// 每次匹配到的结果  exec 获取 {{name}}
        while (match = defaultTagRE.exec(text)) {
            // console.log(match) 获取到 又{{}}  元素
            //  console.log(match)
           let index = match.index;// 保存匹配到的索引
          // hello{{name}} ? {{num}}
            if (index > lastIndex) {
               tokens.push(JSON.stringify(text.slice(lastIndex,index))) //添加的是文本
            }
            //{{name}} 添加{{}} aa
            tokens.push(`_s(${match[1].trim()})`)
            lastIndex = index+match[0].length //最后 {{}} 索引位置
        }
        // 判读最后{{}}的位置是否小于当前文本的位置,如果是,说明还有未解析的文本
        if(lastIndex<text.length){
           tokens.push(JSON.stringify(text.slice(lastIndex))) 
        }
        //最终返回出去

        return `_v(${tokens.join("+")})`
    }
}

trim()去除空格,但是trim是VB/VBScript的字符串处理函数,JS并没有同名或同功能的函数为了能更好的实现功能可以使用正则replace(/(^\s)|(\s$)/g

上一篇下一篇

猜你喜欢

热点阅读