Vue 模板语法——列表渲染(2)

809 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

1. 在 <template> 中使用 v-for

类似于 v-if,我们也可以在 <template> 元素上使用 v-for 来循环渲染一块包含多个元素的内容。

示例:

<template id="my-app">
  <ul>
    <template v-for="(value, key) in info">
      <li>{{ key }}</li>
      <li>{{ value }}</li>
      <li class="divider"></li>
    </template>
  </ul>
</template>
.divider {
  list-style-type: none;
  height: 1px;
  background-color: #999;
  margin: 10px 0;
}
data() {
  return {
    info: {
      name: 'coderzhj',
      age: 20, 
      height: 1.88
    }
  }
}

完整代码如下:

<!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>

  <style>
    .divider {
      list-style-type: none;
      height: 1px;
      background-color: #999;
      margin: 10px 0;
    }
  </style>
</head>
<body>
  <div id="app"></div>

  <template id="my-app">
    <ul>
      <template v-for="(value, key) in info">
        <li>{{ key }}</li>
        <li>{{ value }}</li>
        <li class="divider"></li>
      </template>
    </ul>
  </template>

  <script src="./js/vue.js"></script>
  <script>
    const App = {
      data() {
        return {
          info: {
            name: 'coderzhj',
            age: 20, 
            height: 1.88
          }
        }
      },
      template: '#my-app'
    };

    Vue.createApp(App).mount('#app');
  </script>
</body>
</html>

渲染的效果:

image-20210724132800919.png

在本示例中,我们使用 <template> 来对多个元素进行包裹,而不是使用 <div>,主要有两个原因:

  1. 如果使用 <div> 元素,那么这多出来的 <div> 元素最终也会被渲染进 DOM 中,这是没有必要的,也可能有点浪费性能,而 <template> 元素则不会被渲染出来;
  2. 此外,在 <ul> 元素中是不推荐使用 <div> 元素的,<ul> 中允许的内容只有 0 或多个 <li><script><template> 元素1(虽然其它元素放在 <ul> 中可能不会报错)。

2. 数组更新检测

Vue 将被侦听的数组的变更方法(这些方法会修改原始数组)进行了包裹,所以它们也将会触发视图更新。这些被包裹的方法包括:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

示例(<body> 中的代码):

<div id="app"></div>

<template id="my-app">
  <h2>电影列表</h2>
  <ul>
    <li v-for="(movie, index) in movies">{{ index + 1 }}. {{ movie }}</li>
  </ul>
  <input type="text" v-model="newMovie">
  <button @click="addMovie">添加电影</button>
</template>

<script src="./js/vue.js"></script>
<script>
  const App = {
    data() {
      return {
        movies: [
          '中国医生',
          '流浪地球',
          '战狼',
          '攀登者'
        ],
        newMovie: ''
      }
    },
    methods: {
      addMovie() {
        // 每次调用 push() 方法都会触发视图更新
        this.movies.push(this.newMovie);
        this.newMovie = '';
      }
    },
    template: '#my-app'
  };

  Vue.createApp(App).mount('#app');
</script>

上面的方法会直接修改原来的数组,所以称之为变更方法,但还有些方法不会修改原来的数组,而是会返回一个新数组,比如 filter()concat()slice()。那么在使用这些非变更方法时,我们就可以将它们返回的新数组赋值给原数组,用新数组替换掉旧数组:

this.movies = this.movies.filter(movie => movie.match(/狼/));

你可能会认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。但事实上,Vue 通过它的 diff 算法使得 DOM 元素得到了最大范围的重用,所以用一个含有原数组中相同元素的数组去替换原数组是很高效的操作。

Footnotes

  1. 参考资料:developer.mozilla.org/en-US/docs/…\