vue源码之mustache简易版 --- 完

前面已经实现了 模板字符串转化为 tokens ,这篇我们将实现 tokens 到 dom字符串的转化

1.获取对象嵌套的数据

        当出现一个需要展示的数据为被多层对象嵌套时,由于js不支持 data[a.b],使得无法获取需要展示的数据,所以需要进行必要的处理

lookup(data, key) {
    //含有嵌套的数据,进行处理来获取数据
    if (key.includes() != -1&&key!=".") {
        let keyArr = key.split(".")
        let temp = data
        keyArr.forEach(item=>{
            temp = temp[item]
        })
        console.log(temp) //150
        return temp
    }
    //不含嵌套的数据,直接返回即可
    return data[key]
}
let data = {
    a: {
        b: {
            c: {
                d: 150
            }
        }
    }
}
let key = "a.b.c.d"
lookup(data, key)

 2.将 tokens 转化为dom字符串

        如下:将

转化为

 代码:

import lookup from "./lookup"

export default function renderTemplate(templateStr, data) {
    let resultStr = '';
    for (const item of templateStr) {
        if (item[0] == 'text') {
            resultStr += item[1]
        }
        if (item[0] == "name") {
            resultStr += lookup(data, item[1])
        }
        if (item[0] == "#") {
           
            for(let i =0;i<data[item[1]].length;i++){
                //简单的数组循环可以 " . " 代替索引
                data[item[1]][i] = {
                    ...data[item[1]][i],
                    ".":data[item[1]][i]
                }
               
                resultStr += renderTemplate(item[2],data[item[1]][i])
            }
        }
    }
    return resultStr.trim()

}   

 

简易版musache完整版

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="box"></div>
    <script src="/xuni/bundle.js"></script>
    <script>
        
        let data = {
            arr: [
                { name: "小王", roles: ['教师', "前端高级工程师"] },
                { name: "小李", roles: ['项目经理', "hr", '母亲'] },
            ]
        }
        let templateStr = `
           
        <ul >
            {{#arr}}
                <li class="a">姓名:{{name}}</li>
                <li>角色:
                    <ol>
                        {{#roles}}
                            <li>{{.}}</li>
                        {{/roles}}
                    </ol>
                </li>
            {{/arr}}   
        </ul>
        `
        let htmlStr = LLz_Template.render(templateStr, data)
        console.log(htmlStr)
        document.querySelector(".box").innerHTML = htmlStr
    </script>
</body>

</html>

 

import becomeEasyToken from "./becomeEasyToken.js"
import renderTemplate from "./renderTemplate.js"
window.LLz_Template =  {
    render(templateStr,data){
       templateStr = templateStr.trim()
        
       let tokens = becomeEasyToken(templateStr)
       
        let domStr = renderTemplate(tokens,data)
        return domStr
           
            
    }
}
export default class Scanner {
    constructor (templateStr ){
        //将模板字符串写到实例身上
        this.templateStr = templateStr
        //指针
        this.pos = 0
        //尾巴,刚开始为字符串本身
        this.tail = templateStr
    }
    //让指针跳过目标,进而扫描后面的内容
    scan(target){
        this.pos += target.length
        this.tail = this.templateStr.substring(this.pos)

    }
    //扫描字符串,直到扫描到目标,返回目标之前的字符串
    scanUtil(target) {
        let recordPosValue = this.pos
        //如果该字符串的第一个元素即该目标的索引不为0时,说明指针还需要往右走
        while(this.tail.indexOf(target)!=0&&this.pos<this.templateStr.length){
          
            this.pos++;
            //尾巴变为pos后面的部分
            this.tail = this.templateStr.substring(this.pos)
        }
         return this.templateStr.substring(recordPosValue,this.pos)
    }
}
import Scanner from "./Scanner"
import foldToken  from "./foldToken";
export default function becomeEasyToken (templateStr){
    let token = []
      //实例化一个扫描器,针对模板字符串工作
      let scanner = new Scanner(templateStr)
      while(scanner.pos<templateStr.length){
          let word;
          word = scanner.scanUtil('{{');
          if(word !=''){
            token.push(["text",word])
          }
         
          scanner.scan('{{')

          word = scanner.scanUtil("}}")
          if(word !=''){
            if(word[0] == "#"){
                token.push(["#",word.substring(1)])
            }else if(word[0]=="/"){
                token.push(['/',word.substring(1)])
            }else{
                token.push(["name",word])
            }
          }
          
          scanner.scan("}}")
          
      }
     
      return foldToken(token)
}
export default function foldToken(tokens) {
    //结果数组
    let nestedTokens = []
    //栈结构,存放小tokens
    let section = [];
    //与nestedTokens指向的是同一数组,该数组为一级数组
    let collentor = nestedTokens
    
    for (const item of tokens) {

        switch (item[0]) {
            case "#":
                //进栈
                section.push(item)
                
                collentor.push(item)
                //创建新一级的数组
                collentor = item[2] = [] 
                break;
            case "/":
                //出栈
                section.pop(item)
                //如果都出完了,则回到一级数组,还没出完则回到其上一级
                collentor =  section.length>0?section[section.length-1][2]:nestedTokens
                break;
            default:
                //仅负责给各级数组添加 "text" 元素
                collentor.push(item)
              
        }
    }
    return nestedTokens;
}
//识别对象嵌套的数据
export default function lookup(data, key) {
    //含有嵌套的数据,进行处理来获取数据
    if (key.includes() != -1&&key!=".") {
        let keyArr = key.split(".")
        let temp = data
        keyArr.forEach(item=>{
            temp = temp[item]
        })

        return temp
    }
    //不含嵌套的数据,直接返回即可
    return data[key]
}
import lookup from "./lookup"

export default function renderTemplate(templateStr, data) {
    let resultStr = '';
   
 
    for (const item of templateStr) {

        if (item[0] == 'text') {
            resultStr += item[1]
        }
        if (item[0] == "name") {
            resultStr += lookup(data, item[1])
        }
        if (item[0] == "#") {
           
            for(let i =0;i<data[item[1]].length;i++){
                //简单的数组循环可以 " . " 代替索引
                data[item[1]][i] = {
                    ...data[item[1]][i],
                    ".":data[item[1]][i]
                }
               
                resultStr += renderTemplate(item[2],data[item[1]][i])
            }
        }
    }
    return resultStr.trim()

}   

mustache告以段落,下一节虚拟DOM和diff算法

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值