Vue源码学习笔记-mustache模板引擎(五)-折叠token

269 阅读1分钟

基于栈的概念

栈FIlO 先进后出

微信截图_20210725233459.png

折叠结果

微信截图_20210804212523.png

// nextTokens.js  利用收集器方式 最终版本
/**
 * 折叠tokens
 * 栈底数组第一位,栈顶-数组尾
 */
export default function nextTokens(tokens) {
  // console.log(tokens)
  // 结果数组
  let nestedTokens = []
  // 栈数字组,存放小token,栈顶(靠近端口的,最新进入的)tokens数组中当前操作的这个tokens小数组
  let sections = []
  // 收集器,初始指向结果数组,引用类型值,所以指向同一个数组
  // 收集器指向会变化,当遇见#的时候,收集器会指向这个token的下表为2的新数组
  let collector = nestedTokens
  for (let i = 0; i < tokens.length; i++) {
    let token = tokens[i]
    switch (token[0]) {
      case '#':
        // console.log(token, '------------')
        // 收集器里放入token,由于是引用类型,所以同时可以push到nestedTokens最终结果中
        collector.push(token)
        // 入栈
        sections.push(token)
        // console.log('collector',  collector,' nestedTokens', nestedTokens, '-----#---0----')
        // 收集器更换, 给token添加下标为2的数组,并更换收集器指向,改变了collector的引用指向,切断了collector,与最终结果的关系
        // 下面等同于 token[2] = []; collector = token[2]
        collector = token[2] = []
        //  console.log('collector',  collector,' nestedTokens', nestedTokens, '-----#----1---')
        // console.log(nestedTokens)
        break;
      case '/':
        // console.log(sections, '-------------')
        // 出栈,pop()会返回弹出的项目
        sections.pop()
        // 改变收集器为栈结构队尾(队尾为栈顶),那项的下标为2的数组
        collector = sections.length > 0 ? sections[sections.length -1][2] : nestedTokens
        break;
      default:
        console.log('collector',  collector,' nestedTokens', nestedTokens, '-----default-------')
        // 如果 没进入栈,则直接结果里存,如果如栈了 就要往栈里 也就是 栈的 【2】数组里存
        collector.push(token)
    }
  }
 return nestedTokens
}

// nextTokens.js 同上 比较好理解的方式
/**
 * 折叠tokens
 * 栈底数组第一位,栈顶-数组尾
 */
export default function nextTokens(tokens) {
  // 结果数组
  let nestedTokens = []
  // 栈数字组,存放小token,栈顶(靠近端口的,最新进入的)tokens数组中当前操作的这个tokens小数组
  let sections = []
  // 收集器
  nestedTokens
  for (let i = 0; i < tokens.length; i++) {
    let token = tokens[i]
    switch (token[0]) {
      case '#':
        // 给这个下标项目为2的项创建一个数组,以收集元素
        // 因为 ["#", "students", 此位置为2是数组]
        token[2] = []
        console.log(token[1],'入栈拉')
        // 压栈(入栈)
        sections.push(token)
        
        break;
      case '/':
        // 出栈,pop()会返回弹出的项目
        let section = sections.pop()
        console.log(section[1],'出栈拉')
        // 刚刚弹出的项还没加入到结果数组中
        nestedTokens.push(section)
        break;
      default:
        // 判断,栈队列当前情况
        if (sections.length === 0) {
          // 没有就返回到结果里
          nestedTokens.push(token)
        } else {
          // 栈里已经有内容了,就在下表为2项目里放token
          sections[sections.length - 1][2].push(token)
        }
    }
  }
  return nestedTokens
}
// parseTp2Tokens.js 模板字符串转tokens
import Scanner from './scaner'
// 折叠token
import nextTokens from './nextTokens'
export default function (tpStr) {
  const tokens = []
  // 创建扫描器
  const ScannerInit = new Scanner(tpStr)
  let words;
  // 扫描器
  while (!ScannerInit.eos()) {
    // 收集开始出现前的文字
    words = ScannerInit.scanUtil('{{')
    if (words !== '') {
      // 存储
      tokens.push(['text', words])
    }
    // 跳过大括号
    ScannerInit.scan('{{')
    words = ScannerInit.scanUtil('}}')
    // 收集标记之间的
    if (words !== '') {
      // 存储
      if (words[0] === '#') {
        // 从下标为1 跳过#号开始存
        tokens.push(['#', words.substring(1)])
      } else if (words[0] === '/') {
        tokens.push(['/', words.substring(1)])
      } else {
        tokens.push(['text', words])
      }
    }
    // 跳过大括号
    ScannerInit.scan('}}')
  }
  // 折叠token
  return nextTokens(tokens)
}
// UMD模块改进 nextTokens.js
import parseTp2Tokens from './parseTp2Tokens'

window.TpEngine = {
  render(tpStr, data) {
    console.log('render函数被调用,命令Scanner工作')
    console.log(parseTp2Tokens(tpStr))
  }
}
// 首页tokens index.html
const tmpStr = `<div>
                    <ol>
                      {{#students}}
                        <li>
                          学生{{item.name}}的爱好<ol>
                          {{#item.hobbies}}
                            <li>
                              {{.}}
                            </li>
                          {{/item.hobbies}}
                          </ol>
                        </li>
                      {{/students}}
                    </ol>
                </div>`
    TpEngine.render(tmpStr)