Vue源码之mustache模板引擎(一)

Vue源码之mustache模板引擎(一)

个人练习结果仓库(持续更新):Vue源码解析


抽空把之前学的东西写成笔记。

学习视频链接:【尚硅谷】Vue源码解析之mustache模板引擎

模板引擎是什么

模板引擎是将数据变为视图最优雅的解决方案。

Vue源码之mustache模板引擎(一)_第1张图片

其中,Vue中的列表渲染指令v-for就是一种模板引擎。而**插值表达式{{}}**便是本次要研究的mustache模板引擎的语法


将数据变为视图的方法

纯DOM法

很笨拙。需要频繁创建节点,添加数据,添加节点。

const arr = [
  {
    'name': 'clz',
    'age': 21,
    'sex': '男'
  },
  {
    'name': 'cc',
    'age': 21,
    'sex': '女'
  },
  {
    'name': '赤蓝紫',
    'age': 21,
    'sex': '男'
  }
]

const list = document.getElementById('list')

for (let i = 0; i < arr.length; i++) {
  const li = document.createElement('li')    // 新建li元素

  const bd = document.createElement('div')
  bd.className = 'bd'
  bd.innerText = arr[i].name + '的基本信息'
  li.appendChild(bd)

  const hd = document.createElement('div')
  hd.className = 'hd'

  for (const item in arr[i]) {
    const p = document.createElement('p')
    p.innerText = item + ': ' + arr[i][item]
    hd.appendChild(p)
  }

  li.appendChild(hd)
  list.appendChild(li)
}

Vue源码之mustache模板引擎(一)_第2张图片


数组join法

本质上就是字符串拼接,只是用过数组join法,可以让结构变得更清晰

const arr = [
  {
    'name': 'clz',
    'age': 21,
    'sex': '男'
  },
  {
    'name': 'cc',
    'age': 21,
    'sex': '女'
  },
  {
    'name': '赤蓝紫',
    'age': 21,
    'sex': '男'
  }
]

for (let i = 0; i < arr.length; i++) {
  list.innerHTML += [
    '
  • ', '
    ' + arr[i].name + '的基本信息
    '
    , '
    ', '

    name: ' + arr[i].name + '

    '
    , '

    age: ' + arr[i].age + '

    '
    , '

    sex' + arr[i].sex + '

    '
    , '
    '
    , '
  • '
    ].join('') }

    ES6的模板字符串法

    • 反引号中,文本可以直接换行
    • 反引号中的${expression}占位符中expression可以为任意的JavaScript表达式,甚至为模板字符串
    const arr = [
        {
            'name': 'clz',
            'age': 21,
            'sex': '男'
        },
        {
            'name': 'cc',
            'age': 21,
            'sex': '女'
        },
        {
            'name': '赤蓝紫',
            'age': 21,
            'sex': '男'
        }
    ]
    
    for (let i = 0; i < arr.length; i++) {
        list.innerHTML += `
          
  • ${arr[i].name} 的基本信息

    name: ${arr[i].name}

    age: ${arr[i].age}

    sex: ${arr[i].sex}

  • `
    }

    模板引擎mustache

    mustache仓库

    mustache是最早的模板引擎库


    <script src="./lib/mustache.js">script>
    <script>
      // console.log(Mustache)
    
      const templateStr = `
        
      {{ #arr }}
    • {{ name }}的基本信息

      name: {{ name }}

      age: {{ age }}

      sex: {{ sex }}

    • {{ /arr }}
    `
    const data = { arr: [ { 'name': 'clz', 'age': 21, 'sex': '男' }, { 'name': 'cc', 'age': 21, 'sex': '女' }, { 'name': '赤蓝紫', 'age': 21, 'sex': '男' } ] } const domStr = Mustache.render(templateStr, data) document.getElementsByClassName('container')[0].innerHTML = domStr
    script>

    引入mustache后,就会后一个Mustache对象,其中有一个方法render就可以用来实现将数据变为视图。

    • render的第一个参数是模板字符串,第二个参数是数据
    • 如果需要使用数据,直接通过{{ }}使用即可
    • 要实现循环的话,则需要用{{ #arr }},{{ /arr }}包住要循环的内容

    mustache的基本使用

    mustache.js

    简单使用

    const templateStr = `
      

    我是{{name}}, 年龄为{{age}}岁

    `
    const data = { name: 'clz', age: 21 } const domStr = Mustache.render(templateStr, data) document.getElementsByClassName('container')[0].innerHTML = domStr

    Vue源码之mustache模板引擎(一)_第3张图片

    循环简单数组

    循环的不是对象数组,而是简单数组时,使用.即可

     const templateStr = `
      {{#arr}}
        

    {{.}}

    {{/arr}}
    `
    const data = { arr: ['red', 'blue', 'purple'] } const domStr = Mustache.render(templateStr, data) document.getElementsByClassName('container')[0].innerHTML = domStr

    Vue源码之mustache模板引擎(一)_第4张图片


    数组嵌套

    就是上面两部分的结合版本。

    const templateStr = `
      
      {{#arr}}
    • {{name}}喜欢的颜色是:
        {{#colors}}
      1. {{.}}
      2. {{/colors}}
    • {{/arr}}
    `
    const data = { arr: [ { name: 'clz', colors: ['red', 'blue', 'purple'] }, { name: 'cc', colors: ['white', 'red', 'black'] } ] } const domStr = Mustache.render(templateStr, data) document.getElementsByClassName('container')[0].innerHTML = domStr

    Vue源码之mustache模板引擎(一)_第5张图片


    布尔值

    和循环类似,通过使用{{#布尔值属性}},{{/布尔值属性}},包住要条件渲染的内容即可

    const templateStr = `
      {{#arr}}
        {{#show}}
          

    {{name}}

    {{/show}} {{/arr}}
    `
    const data = { arr: [ { name: 'clz', show: true }, { name: 'czh', show: false } ] } const domStr = Mustache.render(templateStr, data) document.getElementsByClassName('container')[0].innerHTML = domStr

    image-20220312214938151


    通过查看DOM树,可以发现和Vue中的v-if指令类似,是压根就没有上DOM树。另外,Vue中的v-show指令则是动态为元素添加或移除display: none;来控制元素的显示与隐藏。


    es6之前使用mustache

    众所周知,es6之前是没有模板字符串(反引号)的。那么方便的使用mustache呢?

    当然,可以使用上面的数组join法,不过,还有一个更方便的方法。

    通过使用script标签,只要添加typetext/template,然后在里面填模板字符串即可(实际上,只要不被浏览器识别即可)

    <script type="text/template" id="templateStr">
      {{#arr}}
        {{#show}}
          <h2>{{name}}</h2>
        {{/show}}
      {{/arr}}
    </script>
    
    <script src="./lib/mustache.js"></script>
    <script>
      const templateStr = document.getElementById('templateStr').innerHTML
    
      const data = {
        arr: [
          {
            name: 'clz',
            show: true
          },
          {
            name: 'czh',
            show: false
          }
        ]
      }
    
      const domStr = Mustache.render(templateStr, data)
    
      document.getElementsByClassName('container')[0].innerHTML = domStr
    </script>
    

    只能说想到这个方法的人太优秀了


    mustache底层原理


    正则表达式实现最简单的mustache


    String.prototype.replace()

    在开始之前,首先需要了解一下字符串的replace方法

    语法

    str.replace(regexp|substr, newSubStr|function)
    

    参数

    • regexp(pattern):一个RegExp 对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉。

    • substr(pattern):一个将被 newSubStr 替换的 字符串。其被视为一整个字符串,而不是一个正则表达式。仅第一个匹配项会被替换。

    • newSubStr (replacement):用于替换掉第一个参数在原字符串中的匹配部分的字符串。该字符串中可以内插一些特殊的变量名。参考使用字符串作为参数。

    • function (replacement):一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。参考指定一个函数作为参数。

    返回值

    一个部分或全部匹配由替代模式所取代的新的字符串。

    const templateStr = `
      

    我是{{name}}, 年龄为{{age}}岁

    `
    const data = { name: 'clz', age: 21 } console.log(templateStr.replace(/\{\{\w+\}\}/g, '123'))

    image-20220313091349829


    可以发现,上面的做法还无法实现,所以研究一下,第二个参数为函数的情况

    变量名 代表的值
    match 匹配的子串。(对应于上述的$&。)
    p1,p2, ... 假如replace()方法的第一个参数是一个RegExp 对象,则代表第n个括号匹配的字符串。(对应于上述的$1,$2等。)例如,如果是用 /(\a+)(\b+)/ 这个来匹配,p1 就是匹配的 \a+p2 就是匹配的 \b+
    offset 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是 'abcd',匹配到的子字符串是 'bc',那么这个参数将会是 1)
    string 被匹配的原字符串。
    NamedCaptureGroup 命名捕获组匹配的对象
    const templateStr = `
      

    我是{{name}}, 年龄为{{age}}岁

    `
    const data = { name: 'clz', age: 21 } templateStr.replace(/\{\{(\w+)\}\}/g, (match, p1, offset, string) => { console.log(match) console.log(p1) console.log(offset) console.log(string) })

    Vue源码之mustache模板引擎(一)_第6张图片

    可以发现,只需要在正则表达式中使用()把要捕获的内容包起来,然后通过replace方法的函数参数中的p1参数获取捕获内容,既然如此,那就可以开始使用正则表达式实现简单的mustache了。


    实现简单的mustache

    const templateStr = `
      

    我是{{name}}, 年龄为{{age}}岁

    `
    const data = { name: 'clz', age: 21 } const render = (templateStr, data) => { return templateStr.replace(/\{\{(\w+)\}\}/g, function (match, p1, offset, string) { return data[p1] // 把正则所匹配的内容替换成return的内容 }) } const domStr = render(templateStr, data) document.querySelector('.container').innerHTML = domStr

    mustache底层tokens原理

    Vue源码之mustache模板引擎(一)_第7张图片

    mustache底层主要干两件事

    • 将模板字符串编译为tokens形式
    • tokens结合数据,解析为dom字符串

    tokens是什么

    • tokens是一个嵌套数组,也可以说是模板字符串的JS表示
    • tokens抽象语法树(AST)、虚拟节点的开山鼻祖

    看下下面的例子,就能明白了


    简单tokens

    模板字符串

    <h2>我是{{name}}, 年龄为{{age}}岁h2>
    

    tokens

    [
        ["text", "

    我是"], ["name", "name"], ["text", ", 年龄为"], ["name", "age"], ["text", "岁

    "
    ] ]

    简单数组情况下的tokens

    模板字符串

    {{#arr}}
      <h2 style="color: {{.}}">{{.}}h2>
    {{/arr}}
    

    tokens

    [
        ["#", "arr", [
            ["text": "

    "], ["name", "."], ["text", "

    "
    ] ]] ]

    嵌套数组情况下的tokens

    模板字符串

    <ul>
      {{#arr}}
        <li>
          {{name}}喜欢的颜色是:
          <ol>
            {{#colors}}
              <li>{{.}}li>
            {{/colors}}
          ol>
        li>
      {{/arr}}
    ul>
    

    tokens

    [
        ["text", "
      "], ["#", "arr", [ ["text", "li"], ["name", "name"], ["text": "喜欢的颜色是:
        "], ["#", "colors", [ ["text", "
      1. "], ["name", "."], ["text", "
      2. "
        ] ]], ["text", "
      "
      ] ]], ["text", "
    "
    ] ]

    查看mustache的tokens

    进入之前下载的源码文件中,ctrl+f,搜索parseTemplate,到该方法最后把返回值存好并打印

    Vue源码之mustache模板引擎(一)_第8张图片


    重新去跑mustache的基本使用的代码,就可以在控制台中看到tokens

    如循环简单数组

    Vue源码之mustache模板引擎(一)_第9张图片

    你可能感兴趣的:(Vue,Vue源码,javascript,vue,Vue源码)