深度学习mustache

Posted 嘴巴嘟嘟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深度学习mustache相关的知识,希望对你有一定的参考价值。

来自视频教学课程笔记

什么是模板引擎

就是将模板文件和数据通过模板引擎生成一个html代码。
模板引擎是将数据变为视图最优雅的解决方案

       var list = [
            name: "张三"
        , 
            name: "王五"
        ]
       var uu=  document.getElementById("uu")
       for(var i=0;i<list.length;i++)
           let liList = document.createElement('li')
           liList.className = 'll'
           liList.innerText = list[i].name
           uu.appendChild(liList)
       
		// 数组
		var list = [
            name: "张三",
            age: 12
        , 
            name: "王五",
            age: 23
        ]
        var uu = document.getElementById("uu")
        for (let i = 0; i < list.length; i++) 
            var str = [
                ' <li>',
                '     <div class="hd"></div>',
                '     <div class="bd">',
                '         <p>姓名'+list[i].name+'</p>',
                '         <p>年龄'+list[i].age+'</p>',
                '     </div>',
                ' </li>'
            ].join('');
            uu.innerHTML += str
        
		// es6
 		var list = [
            name: "张三",
            age: 12
        , 
            name: "王五",
            age: 23
        ]
        var uu = document.getElementById("uu")
        for (let i = 0; i < list.length; i++) 
            uu.innerHTML += `
                 <li>
                     <div class="hd"></div>
                     <div class="bd">
                         <p>姓名$list[i].name</p>
                         <p>年龄$list[i].age</p>
                     </div>
                </li
            `
            str
        

开始使用mustache


<ul>
  # users
    <li><img src=" gravatar ">  login </li>
  / users
</ul>
var list = [
            name: "张三",
            age: 12
        , 
            name: "王五",
            age: 23
        ]
        // 循环遍历数组
        var templateSter = `
            <ul>
                #list
                 <li>
                 
                     <div class="hd"></div>
                     <div class="bd">
                         <p>姓名name</p>
                         <p>年龄age</p>
                     </div>
                </li>
                /list
            </ul>
            `
        var mustacheStr = Mustache.render(templateSter, list)
        document.getElementById("uu").innerHTML = mustacheStr

        var templateStr2 = `
        <h3>things</h3>
        `
        var obj = 
            things: '我买东西了',
            mood: "开心"
        
        document.getElementById("uu").innerHTML = Mustache.render(templateStr2, obj)

Mustache 核心原理

  1. 不能用简单正则处理
  2. mustache 的底层 token 思想
    mustache 模板引擎的作用是将字符串模板变为 dom 模板,最后结合数据挂载到 dom 树上,在页面渲染呈现。这个过程中,mustache 引入了一个名为 tokens 的概念.

    我们可以通过修改 mustache 源码的方式直接在浏览器控制台打印输出 tokens:
    在源码中找到 parseTemplate 函数,然后在该函数的函数体末尾处,
    return 的 nestTokens(squashTokens(tokens)) 其实就是 tokens
const myTokens = nestTokens(squashTokens(tokens))
console.log(myTokens)
return myTokens

手写mustache

实现将模板字符串编译为 tokens

1、准备阶段

项目文件结构

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="../src/index.js"></script>
    <h1>我是index.html</h1>
</body>
</html>

webpack.config.js

const path = require('path');

module.exports = 
    // 模式开发
    mode: 'development',
    // 入口
    entry: './src/index.js',
    // 打包文件
    output: 
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
    ,
    // 配置webpack-dev-server
    devServer: 
        // 静态个目录
        contentBase: path.join(__dirname, 'www'),
        // 不压缩
        compress: false,
        port: 8080,
        // 虚拟打包的路径
        publicPath: "/xuni/"
    
;

package.json


  "name": "y",
  "version": "1.0.0",
  "description": "",
  "module": "true",
  "main": "index.js",
  "scripts": 
    "test": "echo \\"Error: no test specified\\" && exit 1",
    "dev": "webpack-dev-server"
  ,
  "author": "",
  "license": "ISC",
  "devDependencies": 
    "webpack": "^4.46.0",
    "webpack-dev-server": "^3.11.3"
  ,
  "dependencies": 
    "webpack-cli": "^3.3.12"
  

实现 Scanner 类
Scanner 类的实例就是一个扫描器,用来扫描构造时作为参数提供的那个模板字符串。

  • 属性

pos:指针,用于记录当前扫描到字符串的位置
tail:尾巴,值为当前指针之后的字符串(包括指针当前指向的那个字符)

  • 方法

scan:无返回值,让指针跳过传入的结束标识 stopTag
scanUntil:传入一个指定内容 stopTag 作为让指针 pos 结束扫描的标识,并返回扫描内容

/**
 * 扫描类
 */
export default class Scanner 
    constructor(templateStr) 
        console.log('构造器', templateStr)
        this.templateStr = templateStr
        this.pos = 0
        // 尾巴  一开始就是模本原文
        this.tail = templateStr
    
    // 功能弱,就是路过内容,没有返回值
    scan(tag) 
        if (this.tail.indexOf(tag) === 0) 
            // tag有多长,就让指针后移多少位a 
            this.pos += tag.length
            this.tail = this.templateStr.substring(this.pos)
        
    
    // 让指针扫描,直到遇见指定内容结束,并且能够给返回结束之前路过的文字
    scanUtile(stopTag) 
        // 开始的时候不是stopTag的时候,到最后的全部字符
        const post_backup = this.pos
        while (this.tail.indexOf(stopTag) != 0 && this.eos()) 
            // 指针移动
            this.pos++;
            // 改变尾巴为从当前指针从这个字符开始,直到最后一个字符
            this.tail = this.templateStr.substring(this.pos)
        
        // 返回扫描的字符串,不包括this.pos
        return this.templateStr.substring(post_backup, this.pos)
    
    // 指针到头
    eos() 
        // 返回一个布尔值
        return this.pos >= this.templateStr.length
    

根据模板字符串生成 tokens
有了 Scanner 类后,就可以着手去根据传入的模板字符串生成一个 tokens 数组了。最终想要生成的 tokens 里的每一条 token 数组的第一项用 name(数据) 或 text(非数据文本) 或 #(循环开始) 或 /(循环结束) 作为标识符。
新建一个 parseTemplateToTokens.js 文件来实现

// parseTemplateToTokens.js
import Scanner from './Scanner.js'
import nestTokens from './nestTokens' // 后面会解释

// 函数 parseTemplateToTokens
export default templateStr => 
    const tokens = []
    const scanner = new Scanner(templateStr)
    let word
    while (!scanner.eos()) 
        word = scanner.scanUntil('')
        word && tokens.push(['text', word]) // 保证 word 有值再往 tokens 里添加
        scanner.scan('')
        word = scanner.scanUntil('')
        /** 
         *  判断从  和  之间收集到的 word 的开头是不是特殊字符 # 或 /, 
         *  如果是则这个 token 的第一个元素相应的为 # 或 /, 否则为 name
         */
        word && (word[0] === '#' ? tokens.push(['#', word.substr(1)]) :
            word[0] === '/' ? tokens.push(['/', word]) : tokens.push(['name', word]))
        scanner.scan('')
    
    return nestTokens(tokens) // 返回折叠后的 tokens, 详见下文


** index.js 引入 parseTemplateToTokens**

// index.js
import parseTemplateToTokens from './parseTemplateToTokens.js'

window.My_TemplateEngine = 
  render(templateStr, data) 
    const tokens = parseTemplateToTokens(templateStr)
    console.log(tokens)
  


在index.html中使用

const templateStr = `
  <ul>
      #arr
        <li>
          <div>name的基本信息</div>
          <div>
            <p>name</p>
            <p>age</p>
            <div>
              <p>爱好:</p>
              <ol>
                #hobbies
                  <li>.</li>
                /hobbies
              </ol>
            </div>
          </div>
        </li>
      /arr
  </ul>
`

实现 tokens 的嵌套

新建 nestTokens.js 文件,定义 nestTokens 函数来做 tokens 的嵌套功能,将传入的 tokens 处理成包含嵌套的 nestTokens 数组返回。
然后在 parseTemplateToTokens.js 引入 nestTokens,在最后 return nestTokens(tokens)。

/**
 * 
 * @param * tokens 
 */
export default function nestTokens(tokens) 
    // 结果数组
    var nestTokens = []
    // 栈结构 栈顶 (靠近端口,最新进入) 的token数组中当前操作的这个tokens小数组
    var sections = []
    // 收集器 天生指向nestedTokens结果数组,引用类性质,所以指向的是同一个数组
    // 收集器指向会变化 当遇到#时候,收集器会指向token为2的新数组
    var collector = nestTokens
    for (let i = 0; i < tokens.length; i++) 
        let token = tokens[i]
        switch (token[0]) 
            case '#':
                // 收集器放入token
                collector.push(token)
                // 压栈
                sections.push(token)
                // 收集器换人
                collector = token[2] = []
                break
            case '/':
                // 出栈 pop()返回刚刚弹出的项
                sections.pop()
                // 改变收集器为栈结构队尾,那项下标为2的数组
                collector = sections.length > 0 ? sections[sections.length - 1][2] : nestTokens
                break;
            default:
                collector.push(token)
                break
        
    
    return nestTokens

遍历 tokens 数组,根据每条 token 的第一项的值来做不同的处理,为 text 就直接把 token[1] 加入到最终输出的 dom 字符串,为 name 则根据 token[1] 去 data 里获取数据,结合进来。
当 data 里存在多层嵌套的数据结构,比如 data = test: a: b: 10 ,这时如果某个 token 为 [“name”, “test.a.b”],即代表数据的 token 的第 2 项元素是 test.a.b 这样的有多个点符号的值,那么我么直接通过 data[test.a.b] 是无法拿到正确的值的,因为 js 不认识这种写法。我们需要提前准备一个 lookup 函数,用以正确获取数据。

定义 lookup 函数

/**
 * 功能是可以在dataObj对象中,寻找用连续点符号的keyName属性
 * 需要师表a.b.c
 */
export default function lookup(dataObj, keyName) 
    // 首先查看keyName 中有没有点符号 但是不能是本身
    if (keyName.indexOf('.') !== -1 && keyName !== '.') 
        var keys = keyName.splice('.')
        // 设置临时变量周转一层一层找下去 
        let temp = dataObj
        for (let i = 0; i < keys.length; i++) 
            temp = temp[keys[i]]
        
        return temp
    
    return dataObj[keyName]

定义 renderTemplate 函数
接下来就可以开始写个 renderTemplate 函数将 tokens 和 data 作为参数传入,解析为 dom 字符串了。

import lookup from './lookup'
import parseArray from './parseArray'

/**
 * 
 */
export default function renderTemplate(tokens, data) 
    for (let i = 0; i < tokens.length; i++) 
        let token = tokens[i]
        let resultStr = ''
        //看类型
        if (token[0] === 'text') 
            resultStr = token[i]
         else if (token[0] === 'name') 
            // 防止“a.b.c”
            resultStr += lookup(token[1])
         else if (token[0] === '#') 
            resultStr += parseArray(token, data)
        
    
    return resultStr


当某个 token 的第一项为 “#” 时,要再次递归调用 renderTemplate 函数。这里我们新定义了一个 parseArray 函数来处理。

import lookup from "./lookup"
import renderTemplate from "./renderTemplate"
/**
 * 处理数组 结合renderTemplate实现递归
 * 这个是函数接收的token
 */

export default function parseArray(token, data) 
    // 得到整体数据中这个数据的使用部分
    var v = lookup(data, token[1])
    var resultStr = ''
    // 遍历数组v 
    // 注意遍历数据而不是tokens
    for (let i = 0; i < v.length; i++) 
        resultStr += renderTemplate(token[2], 
            ...v[i],
            '.': v[i]
        )
    
    return resultStr

以上是关于深度学习mustache的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序入门——Mustache语法学习

Java类模本

Servlet和模本办法

Smarty模本引擎

5.1mustache

Pytorch深度学习50篇·······第五篇:YOLO-----训练篇