vue源码的学习之数据的渲染

182 阅读4分钟

vue源码之数据渲染为视图

前言:vue是如何将从后台获取的数据显示到我们的页面中的呢,其实他是使用了mustache引擎,这东西其实就是将数据变为视图的一种解决方式,那么为啥要用这种解决方式呢?其实在数据转视图的发展史中,有过很多的解决方法,但是mustache引擎是最为优雅的一种方式,下面让我们来分别列举并对比各种数据转视图的方式。

数据转视图的几种方式

1.原生DOM -- 贼麻烦

<!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>
    <ul id="list"></ul>
    <script>
      var list = [{ name: "wsj" }, { name: "ddd" }, { name: "study" }]
      var ulList = document.getElementById("list")
      for (var i = 0; i < list.length; i++) {
        //   每次遍历数组的其中一项,都要使用dom方法去创建li标签
        let oLi = document.createElement("li")
        oLi.innerText = list[i].name
        // 将创建的节点插入到UL中
        ulList.appendChild(oLi)
      }
    </script>
  </body>
</html>

一顿操作猛如虎,结果渲染个二百五,这种方法需要不停的创建和插入dom,灰常不人性化

QQ图片20220109232029.png

2.数组join法-- 其实就是在DOM的基础上升个级

<!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>
    <ul id="list"></ul>
    <script>
      var list = [{ name: "wsj" }, { name: "ddd" }, { name: "study" }]
      var uLi = document.getElementById("list")
      for (var i = 0; i < list.length; i++) {
        // 遍历数组,每次遍历,以字符串的形式将html字符串添加到list中
        uLi.innerHTML += [
          "<li>",
          '<div class ="hd"></div>',
          '<div class ="bd">',
          "<p>姓名:" + list[i].name + "</p>",
          "</div>",
          "</li>",
        ].join("")
      }
    </script>
  </body>
</html>

他的原理就是利用数组的join方法将数组转换成html格式的字符串,然后将字符串插入到DOM的innerHTML中,比原生DOM削微效率高点!

QQ截图20220109233614.png

3.反引号法 -- ES6语法代替数组join法

<!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>
    <ul id="list"></ul>
    <script>
      var list = [{ name: "wsj" }, { name: "ddd" }, { name: "study" }]
      var uLi = document.getElementById("list")
      for (var i = 0; i < list.length; i++) {
        // 遍历数组,每次遍历,以字符串的形式将html字符串添加到list中
        uLi.innerHTML += ` <li>
          <div class ="hd"></div>
          <div class ="bd">
          <p>姓名:${list[i].name}</p>
          </div>
          </li>`
      }
    </script>
  </body>
</html>

其实就是将数组的join法做了一个优化替换,得到的结果和join法一模一样

QQ截图20220109233614.png

4.Mustache方法

Mustache(胡子)模板其实就是我们在vue中常见的双大括号展示数据的方法,工作原理是利用形似胡子的双大括号将数据循环至DOM字符串中,并生成一个新的DOM字符串,然后我们再将这个新的DOM字符串添加至DOM元素中的innerHTML中实现数据渲染,主要使用其暴漏的Mustache.render方法实现。下面我们介绍一下Mustache的基本使用方法和render方法。

数据循环

①.首先将Mustache.js导入到我们本地,下面是文件地址

cdn.bootcdn.net/ajax/libs/m…

②.引入Mustache.js文件到我们的script标签中

<script src="./mustache.js"></script>

③.创建一个DOM字符串

## 首先创建一个dom字符串,其中{{#arr}}{{/arr}}是mustache中的循环语法,你可以将其理解成为vue中的v-for
    var domStr = `
    <ul>
      {{#arr}}
       <li>
          <div class='hd'>Mustache模板</div>
          <div class='bd'>
              <p>{{name}}</p>
          </div>
       </li>
      {{/arr}}
      </ul>
  `

④.新建一个对象存放需要遍历的数据

    var data = {
      arr: [{ name: "wsj" }, { name: "ddd" }, { name: "study" }],
    }

⑤.使用render方法将domStr转换成我们需要的DOM字符串

*render方法有两个参数,第一个是需要转换的字符串,也就是我们上面有mustache双大括号的字符串,第二个参数就是存放数据的对象,注意对象中的属性名必须是我们mustache循环语法中所用到的名称*

  const listStr = mustache.render(domStr, data)
  ## 我们将其打印出来
  console.log(listStr)

可以看到我们打印出的数据跟我们使用上面三种方法生成的DOM字符串一样 ⑥.将DOM字符串添加至dom的innerHTML中

var list = document.getElementById("list")
list.innerHTML = listStr

最终在浏览器中的结果:

QQ截图20220110231317.png

简单数据循环

mustache也可以进行简单数据循环,上述的数据arr数组里面是对象,如果其中是字符串的话,我们可以用{{.}}进行渲染

  var domStr = `
        <ul>
          {{#arr}}
           <li>
              <div class='hd'>Mustache模板</div>
              <div class='bd'>
                  <p>{{.}}</p>
              </div>
           </li>
          {{/arr}}
          </ul>
      `
      // 2.创建一个对象,存放需要遍历的数据
      var data = {
        arr: ["wsj", "ddd", "study "],
      }

数组的嵌套

mustache相比其他方法,其优势不仅仅在于代码的优雅展示,更在于对嵌套数组的处理,数组中嵌套数组,我们直接在双大括号中添加嵌套的数组名即可

    var domStr = `
        <ul>
          {{#arr}}
           <li>
            {{name}}的爱好:
            <ol>{{hobbies}}</ol>
           </li>
          {{/arr}}
          </ul>
      `
      // 2.创建一个对象,存放需要遍历的数据
      var data = {
        arr: [
          { name: "wsj", hobbies: ["吃饭", "睡觉", "打豆豆"] },
          { name: "ddd", hobbies: ["跑步", "游泳", "骑行"] },
          { name: "study", hobbies: ["打游戏"] },
        ],
      }

结果展示:

QQ截图20220110233628.png 代码优化:

 var domStr = `
        <ul>
          {{#arr}}
           <li>
            {{name}}的爱好:
            	<ol>
            	{{#hobbies}}
            		<li>{{.}}</li>
				{{/hobbies}}
           	    </ol>
           </li>
          {{/arr}}
          </ul>
      `
      // 2.创建一个对象,存放需要遍历的数据
      var data = {
        arr: [
          { name: "wsj", hobbies: ["吃饭", "睡觉", "打豆豆"] },
          { name: "ddd", hobbies: ["跑步", "游泳", "骑行"] },
          { name: "study", hobbies: ["打游戏"] },
        ],
      }

布尔值的应用

如果数据对象中存在一个布尔值,我们可以利用其控制数据的显示与隐藏,你可以将其理解为vue的v-if

 var domStr = `
        <ul>
            {{#B}}
                 Hello World
            {{/B}}
            {{#A}}
                You can see me 
            {{/A}}
          </ul>
      `
       var data = {
        B: false,
        A: true,
      }

结果展示:

QQ截图20220110234911.png 可以看出,Hello World 被隐藏了,因为其对应的值为false

DOM字符串的优化

我们可以将反引号中的字符串用script包裹起来,但是该script标签的type属性必须是不能被浏览器检测到的类型,(否则会被当作js逻辑被执行),然后再利用getElementById获取该标签,这样做的好处在于,不用反引号的结构可以更直观,也会被vscode格式化

 <body>
    <div id="list"></div>
    <script src="./mustache.js"></script>
    <script type="text/template" id="domStr">
      <ul>
          {{#arr}}
           <li>
            {{name}}的爱好:
            <ol>
                {{#hobbies}}
                <li>{{.}}</li>
                {{/hobbies}}
            </ol>
           </li>
          {{/arr}}
          </ul>
    </script>
    <script>
      // 向外暴漏一个mustache对象
      //   console.log(mustache)
      // 1.获取script标签
      const domStr = document.getElementById("domStr").innerHTML
      // 2.创建一个对象,存放需要遍历的数据
      var data = {
        arr: [
          { name: "wsj", hobbies: ["吃饭", "睡觉", "打豆豆"] },
          { name: "ddd", hobbies: ["跑步", "游泳", "骑行"] },
          { name: "study", hobbies: ["打游戏"] },
        ],
      }
      // 3.使用mustache.render()方法,其中有两个参数,第一个放dom字符串,第二个存放需要转换为视图的数据
      const listStr = mustache.render(domStr, data)
      console.log(listStr)
      // 4.把mustache生成的dom结构字符串添加至dom元素中
      var list = document.getElementById("list")
      list.innerHTML = listStr
    </script>
  </body>

结果展示:

QQ截图20220110235822.png

最终总结:

四种不同的方法都是生成DOM字符串,然后将其添加至DOM的innerHTML中,但是明显的一代更比一代强,经过技术不断地迭代更新,大佬们研究出了mustache模板,通过其render方法(几乎只用这个方法),可以优雅的将数据渲染至DOM中,而我们所需要研究的不仅仅是mustache怎么使用,而是其在vue中所担当的角色,以及其底层原理。下篇文章讲述的是mustache的底层原理以及在vue中的实现。