# 插值语法—文本

将 data 中数据插入到 HTML 模版内容中

# Mustache 语法 🔥

Mustache 语法,双大括号

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue</title>
  </head>

  <body>
    <div id="app">
      <h2>{{message}}</h2>
      <h2>{{message}}李银河</h2>
      <!-- 表达式 -->
      <h2>{{lastName + firstName}}</h2>
      <h2>{{lastName + " "+firstName}}</h2>
      <h2>{{lastName}}@{{firstName}}</h2>
      <h2>{{count*2}}</h2>
    </div>

    <script src="./lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          message: "你好!",
          firstName: "三",
          lastName: "张",
          count: 100,
        },
      });
    </script>
  </body>
</html>

Mustache 标签将会被替代为对应 data 数据对象上属性的值

无论何时,绑定的 data 数据对象上属性发生了改变,插值处的内容都会更新。

Mustache 中存放的是变量对象,也可以放表达式、方法(最后需带括号)(不推荐),若用引号引用则视作字符串不再解析。

# v-once 指令 🔥

只渲染元素组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <!-- 单个元素 -->
      <h2>This will change: {{message}}</h2>
      <h2 v-once>This will never change: {{message}}</h2>

      <!-- 有子元素 -->
      <div>
        <h2>{{message}}</h2>
      </div>
      <div v-once>
        <h2>{{message}}</h2>
      </div>

      <!-- 组件 -->
      <my-component v-once :comment="message"></my-component>
      <my-component :comment="message"></my-component>

      <!-- `v-for` 指令-->
      <ul>
        <li v-for="i in list" :key="i">{{i}}</li>
      </ul>
      <ul>
        <li v-for="i in list" :key="i" v-once>{{i}}</li>
      </ul>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      // 这里写的组件必须在 new Vue() 前定义!
      Vue.component("my-component", {
        data: function () {
          return {
            count: 0,
          };
        },
        props: {
          comment: "",
        },
        template: "<h1>{{comment}} my-component</h1>",
      });

      const vm = new Vue({
        el: "#app",
        data: {
          message: "Test 1",
          list: [1, 2, 3],
        },
        methods: {},
      });
    </script>
  </body>
</html>

# v-text 指令

作用和 Mustache 相似,更新元素的 textContent。但是会覆盖该标签的内容!不灵活,一般使用较少!如果要更新部分的 textContent ,需要使用 插值。

# v-html 指令 🔥

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      mustache:
      <span>{{url}}</span><br />

      v-html:
      <span v-html="url"></span><br />

      v-text:
      <span v-text="url"></span><br />
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          message: "Hello",
          url: '<a href="https://www.qq.com">QQ</a>',
        },
        methods: {},
      });
    </script>
  </body>
</html>

属性值会直接作为 HTML——会忽略解析属性值中的数据绑定。注意,你不能使用 v-html 来复合局部模板,因为 Vue 不是基于字符串的模板引擎。反之,对于用户界面 (UI),组件更适合作为可重用和可组合的基本单位。

# v-pre 指令 🔥

<pre>跳过这个元素和它的子元素编译过程。可用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <span v-pre>{{ this will not be compiled }}</span>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>

# v-cloak 指令

cloak

披风; 斗篷; 大衣; 氅。这里为挡住之类的意思。

区别 clock 时钟

这个指令保持在元素上直到关联实例结束编译,可以据此来实现判断。

上述含义为,在 Vue 编译完前 HTML 中有 v-cloak 属性,在 Vue 编译完后该属性被删掉。

基本也不会使用,以后这个模版会渲染为函数,和虚拟DOM有关,不会显示 mustache 语法的。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
    <style>
      /* 属性选择器 */
      [v-cloak] {
        display: none;
      }
    </style>
  </head>

  <body>
    <div id="app">
      <h2 v-cloak>{{message}}</h2>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      setTimeout(() => {
        const vm = new Vue({
          el: "#app",
          data: {
            message: "Hello",
          },
          methods: {},
        });
      }, 2000);
    </script>
  </body>
</html>

# 过滤器 🔥

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue</title>
    <style>
      table {
        /* 合并细线边框 */
        border-collapse: collapse;
        /* 单元格之间水平、垂直距离,与 border-collapse 冲突,不常用 */
        /*border-spacing: 10px 20px;*/
        /* 表格居中 */
        margin: 100px auto;
      }
      th,
      td {
        /* 边框 */
        border: 1px solid skyblue;
        /* 内边距 */
        padding: 20px;
        /* 让td居中,th本来就是居中的 */
        text-align: center;
        /* 默认情况下元素在th,td中是垂直居中的,也可以通过 vertical-align 来修改*/
        /* 由此可得,对一个父元素设置 display: table-cell,可以直接使用 vertical-align 来垂直居中*/
      }
    </style>
  </head>

  <body>
    <div id="app">
      <div v-if="books.length >= 1">
        <table>
          <thead>
            <tr>
              <th></th>
              <th>书籍名称</th>
              <th>出版日期</th>
              <th>价格</th>
              <th>购买数量</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(book,index) in books" :key="book.id">
              <td>{{book.id}}</td>
              <td>{{book.name}}</td>
              <td>{{book.time}}</td>
              <!-- <td>{{'¥'+book.price.toFixed(2)}}</td> -->
              <!-- 这么多地方使用,可以复用 -->
              <!-- 方式1:方法。计算属性也可以 -->
              <!-- <td>{{formartPrice(book.price)}}</td> -->
              <!-- 方式2:过滤器 -->
              <td>{{book.price | formartPrice}}</td>

              <td>
                <button @click="decrement(book)" :disabled="book.count === 1">
                  -
                </button>
                {{book.count}}
                <button @click="increment(book)">+</button>
              </td>
              <td><button @click="remove(index)">移除</button></td>
            </tr>
          </tbody>
        </table>
        <!-- 总价:{{'¥'+totalPrice.toFixed(2)}} -->
        <!-- 总价:{{formartPrice(totalPrice)}} -->
        总价:{{totalPrice | formartPrice}}
      </div>
      <div v-else>
        购物车为空
      </div>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      // vue.js文件中定义了 Vue 对象,使用时可以 new 构造出,并且它还有参数(对象类型)
      const vm = new Vue({
        el: "#app",
        // 声明式编程(声明式渲染),不再使用命令式
        data: {
          books: [
            { id: 1, name: "Java", time: "2006-02", price: 110.0, count: 1 },
            { id: 2, name: "Kotlin", time: "2016-03", price: 120.0, count: 1 },
            { id: 3, name: "Clojure", time: "2008-12", price: 112.0, count: 1 },
            { id: 4, name: "JVM", time: "2002-8", price: 200.0, count: 1 },
          ],
        },
        methods: {
          increment(book) {
            book.count++;
          },
          decrement(book) {
            // if (book.count === 1) {
            //   return;
            // }
            book.count--;
          },
          remove(index) {
            this.books.splice(index, 1);
          },
          formartPrice(price) {
            return "¥" + price.toFixed(2);
          },
        },
        computed: {
          totalPrice() {
            // let totalPrice = 0;
            // this.books.forEach((item) => {
            //   totalPrice += item.price * item.count;
            // });
            // return totalPrice;

            return this.books.reduce((previous, current, index, arr) => {
              return previous + current.price * current.count;
            }, 0);
          },
        },
        filters: {
          formartPrice(price) {
            return "¥" + price.toFixed(2);
          },
        },
      });
    </script>
  </body>
</html>