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

news2024/11/17 12:44:58

前面已经实现了 模板字符串转化为 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算法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1697669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法的时间与空间复杂度

算法是指用来操作数据、解决程序问题的一种方法。对于同一问题&#xff0c;使用不同的算法&#xff0c;也许最终结果是一样的&#xff0c;但在过程中消耗的资源和时间却会有很大的区别。 那我们该如何去衡量不同算法之间的优劣呢&#xff1f;主要还是从算法所占用的【时间】和…

Anaconda+CUDA+CUDNN+Pycharm+Pytorch安装教程(第一节 Anconda安装)

1.选择和对应的anconda版本 官网地址&#xff1a;Index of / (anaconda.com) 下载地址&#xff1a;Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.安装流程 (1)下载安装包 (2)点击next &#xff08;3&#xff09;点击I agree &a…

MySQL--联合索引应用细节应用规范

目录 一、索引覆盖 1.完全覆盖 2.部分覆盖 3.不覆盖索引-where条件不包含联合索引的最左则不覆盖 二、MySQL8.0在索引中的新特性 1.不可见索引 2.倒序索引 三、索引自优化--索引的索引 四、Change Buffer 五、优化器算法 1.查询优化器算法 2.设置算法 3.索引下推 …

【Java】/*类和对象(上)*/

目录 一、什么是类&#xff0c;什么是对象 二、类和对象的关系 三、学习类和对象的目的 四、怎样创建一个类 4.1 语法形式 4.2 创建示例 示例一&#xff1a;日期对象 示例二&#xff1a;小狗对象 示例三&#xff1a;学生对象 4.3 注意事项 4.4 修改public修饰的主类…

css卡片翻转 父元素翻转子元素不翻转效果

css卡片翻转 父元素翻转子元素不翻转效果 vue <div class"moduleBox"><div class"headTitle"><span class"headName">大额案例</span></div><div class"moduleItem"><span class"module…

java 拦截器-用户无操作超时退出利用Redis

1、授权过滤&#xff0c;只要实现AuthConfigAdapter接口 2、利用Redis token超时时间&#xff0c;用户访问后台续时 效果 Component public class AuthFilter implements Filter {private static Logger logger LoggerFactory.getLogger(AuthFilter.class);Autowiredprivat…

《python编程从入门到实践》day39

# 昨日知识点回顾 创建主页、继承模版、显示特定主题页面 # view.py from django.shortcuts import render# 导入所需数据相关联的模型 from .models import Topic# Create your views here. def index(request):"""学习笔记的主页"""#…

GB报文中的Cseq值的注意点

一、 问题现象 【问题现象】NVR使用GB接三方平台发现倍速回放时&#xff0c; 【现场拓扑】现场拓扑如下 &#xff08;1&#xff09; NVR侧使用家用宽带的方式&#xff0c;通过国标跨公网接入三方平台。 图1.1&#xff1a;网络拓扑 二、 抓包分析 INVITE sip:420000004013200…

ABC354学习笔记

高桥有一棵植物&#xff0c;这个植物在第 0 0 0 天时高度为 0 c m 0\,\mathrm{cm} 0cm&#xff0c;此后的第 i i i 天&#xff0c;他的植物会增高 2 i c m 2^i\,\mathrm{cm} 2icm。 高桥身高为 H c m H\,\mathrm{cm} Hcm。 高桥想知道在第几天&#xff0c;他的植物的高度会…

grpc、多集群、多租户

gRPC和服务发现 一个A high-performance, open-source universal RPC framework&#xff0c;高性能、开源的通用 RPC 框架。使用protobuf 语言基于文件定义服务&#xff0c;通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub。移动端上面则是基于标准的 HTTP…

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(十三)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 我们&#xff0c;继续讲一…

如何将前端项目打包并部署到不同服务器环境

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈&#xff08;笔记是根据b站尚硅谷的前端讲师【张天禹老师】整理的&#xff0c;用于自己复盘&#xff0c;有需要学习的可以去b站学习原版视频&…

three.js判断物体在人的前面,还是后面

three.js判断物体在人的前面&#xff0c;还是后面 const player new THREE.Vectors(10, 0, 5); const mesh new THREE.Vectors(15, 0, 6);上面&#xff0c;两个变量分别表示&#xff0c;玩家的位置&#xff0c;物体的位置。 从这发现&#xff0c;当玩家和物体的角度关系 小…

网络协议——RTSP(简介、搭建RTSP服务器)

一、简介 1、什么是RTSP RTSP&#xff08;Real-Time Streaming Protocol&#xff0c;实时流传输协议&#xff09;是一种网络应用协议&#xff0c;旨在用于在互联网上进行娱乐和通信的实时流媒体的控制。它允许客户端远程控制媒体服务器上的流媒体播放&#xff0c;例如播放、暂…

决定新泽西州版图的关键历史事件

决定新泽西州版图的关键历史事件 1. *民地建立&#xff1a;1664年&#xff0c;新泽西成为英国*民地。该地区原为荷兰*民地的一部分&#xff0c;但同年根据英王查理二世的赐予&#xff0c;转归给了他的兄弟约克公爵&#xff08;后来的詹姆士二世&#xff09;&#xff0c;之后又被…

Matlab 结构光相移法(单频多相)

文章目录 一、简介1、基于点的测距2、基于条纹的测距二、条纹编码2.1 二进制编码2.2相移法三、实现代码参考文献一、简介 在介绍相移法之前,我们需要先了解一下为啥会有相移法,了解了其来龙去脉,则更容易去应用它。 1、基于点的测距 首先我们从点的测距开始,这有点类似于立…

C++笔试强训day33

目录 1.跳台阶扩展问题 2.包含不超过两种字符的最长子串 3.字符串的排列 1.跳台阶扩展问题 链接https://www.nowcoder.com/practice/953b74ca5c4d44bb91f39ac4ddea0fee?tpId230&tqId39750&ru/exam/oj 我是用动态规划解决的&#xff1a; #include <iostream>…

Oracle 并行和 session 数量的

这也就是为什么我们指定parallel为4&#xff0c;而实际并行度为8的原因。 insert create index&#xff0c;发现并行数都是加倍的 Indexes seem always created with parallel degree 1 during import as seen from a sqlfile. The sql file shows content like: CREATE INDE…

【傻呱呱】python安装phook3(Windows端)

前期准备 swig程序Visual Studio C 构建工具 配置swig程序 将下载好的“swig-4.2.1”压缩包解压到C盘从C盘打开“swig-4.2.1”文件夹并复制文件夹路径 在开始菜单里搜索“环境变量”&#xff0c;点击“编辑系统环境变量” 点击“环境变量” 找到“path”并双击 点击“新建” …

K8S认证|CKA题库+答案| 13. sidecar 代理容器日志

目录 13、使用 sidecar 代理容器日志 CKA v1.29.0模拟系统 下载试用 题目&#xff1a; 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、生成yaml文件 3&#xff09;、官网找模板 4&#xff09;、编辑yaml文件 5&#xff09;、应用yaml文件 ​6&…