vue2的模版编译 对children的字符串拼接

186 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第26天,点击查看活动详情

vue2模版编译 render 方法 属性格式化介绍 这边文章把属性格式化介绍完了,我们继续下面的逻辑,下面我们就要处理el的子元素了,咱们可以看下AST的结构如图

vue1.png 我们来看下代码

function generate(el) {
   // 拿到children的方法
   let children = getChildren(el) // 可以把子元素直接拼在后面
   let code = `
      _c(${el.tag},
         ${el.attrs.length>0?`${formProps(el.attrs)}`:'undefined'}
         ${children?`,${children}`:','}
        ) 
   `
}

getChildren方法

// 使用的正则表达式
// 获取
function getChildren(el) {
   // 循环子元素并且对返回字符串进行拼接
  const children = el.children;
  if (children) {
    // 这里我们需要拼接字符串
    return children.map(c=>{
       return generateChild(c).jion(',')
    })
  }
}

generateChild方法又是一个非常复杂的一个方法,我们又要拼接字符串了

// 拼接children的的方法
function generateChild(node) {
   // 优先判断是不是AST的type值
   if (node.type==1) { // 直接走generate的逻辑
     return generate(node)
   } else if (node.type==3) { // 如果是文本类型
    let text = node.text
      // 这里也需要判断是纯文本还是有双大括号纯文本好做
      if (!defaultTagRE.test(text)) {
        return `_v('${node.text}')`
      }
      // 处理有双大括号的文本最麻烦
      let match,index;
      let lastIndex = defaultTagRE.lastIndex = 0; 
      let textArr = []; // 每一次截取出来的都放在这个数组里
      // lastIndex是正则表达是捕获的一个属性,他是会累计的,每捕获成功一次会相加等于10,第两次捕获就会从10开始,就不会从零开始
      while (match=defaultTagRE.exec(text)) { // 正则捕获
        console.log(match)
        // 我们会把match打印出来看一下更加明确
         index = match.index;  // index是捕获到开始位置
         if (index>lastIndex) { // 说明有大括号
            // 这是截取大括号之前的文本
            textArr.push(JSON.stringify(text.slice(lastIndex,index)))
         }
         textArr.push(`_s(${match[1].trim()})`)
         lastIndex = index+ match[0].length

      }
      if (lastIndex<text.length) { // 判断lastIndex是是否小于文本长度
        // 小于说明还有文本
        textArr.push(`${JSON.stringify(text.slice(lastIndex))}`)
      }
      console.log(textArr)
      console.log(`_v(${textArr.join('+')})`)
      return `_v(${textArr.join('+')})`
   }
}

大家可以看下打印出的match和textArr

vue1.png 上面是match 下面是textArr

可以看下已经拼接好的字符串

vue2.png