阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      Vue.js v-for

      v-for

      • 预期Array | Object | number | string | Iterable (2.6 新增)

      用法

      基于源数据多次渲染元素或模板块。此指令之值,必须使用特定语法 alias in expression ,为当前遍历的元素提供别名:

      <div v-for="item in items">
        {{ item.text }}
      </div>
      

      另外也可以为数组索引指定别名 (或者用于对象的键):

      <div v-for="(item, index) in items"></div>
      <div v-for="(val, key) in object"></div>
      <div v-for="(val, name, index) in object"></div>
      

      v-for 的默认行为会尝试原地修改元素而不是移动它们。要强制其重新排序元素,你需要用特殊属性 key 来提供一个排序提示:

      如果该数组可能是会变化的,不要使用 index 作为 key,可以使用固定的某个值,比如user_id

      <div v-for="item in items" :key="item.id">
        {{ item.text }}
      </div>
      

      数组中使用 v-for

      <div id="app">
        <ul>
          <li v-for="(item, index) in list">
            index: ${ index }, name: ${ item.name }
          </li>
        </ul>
      </div>
      
      var vm = new Vue({
        el: '#app',
        delimiters: ['${', '}'],
        data: {
          list: [
            { id: '123456789', name: ' 1111' },
            { id: '234567890', name: ' 2222' },
            { id: '345678901', name: ' 3333' },
          ],
        },
      });
      

      对象中使用 v-for

      <div id="app">
        <ul>
          <li v-for="(item, key, index) in list">
            index: ${ index }, key: ${ key }, name: ${ item.name }
          </li>
        </ul>
      </div>
      
      var vm = new Vue({
        el: '#app',
        delimiters: ['${', '}'],
        data: {
          list: {
            '123456789': { name: '選項 1' },
            '234567890': { name: '選項 2' },
            '345678901': { name: '選項 3' },
          },
        },
      });
      

      在迭代中使用 v-for

      div>
        <span v-for="n in 10">${ n }</span>
      </div>
      

      <template标签

      <div id="app">
        <ul>
          <template v-for="(item, index) in list">
            <li>index: ${ index }, name: ${ item.name }</li>
          </template>
        </ul>
      </div>
      

      其他

      从 2.6 起,v-for 也可以在实现了可迭代协议的值上使用,包括原生的 MapSet。不过应该注意的是 Vue 2.x 目前并不支持可响应的 MapSet 值,所以无法自动探测变更。

      当和 v-if 一起使用时,v-for 的优先级比 v-if 更高。详见列表渲染教程

      v-for 的详细用法可以通过以下链接查看教程详细说明。

      参考

      Key 说明

      由于效能考虑,在默认的状况下,Vue.js 会尽量重复使用已渲染好的元素。

      若不设定 key 值,不会重新渲染元素,只会部份更新。

      不使用 Key 的演示

      <div id="app">
        <ul>
          <li v-for="(item, index) in list">${ index } <input type="text" :placeholder="item.name" /></li>
        </ul>
      </div>
      
      var vm = new Vue({
        el: '#app',
        delimiters: ['${', '}'],
        data: {
          list: [
            { id: '123456789', name: '選項 1' },
            { id: '234567890', name: '選項 2' },
            { id: '345678901', name: '選項 3' },
          ],
        },
      });
      

      初始画面,用户分别在每个输入框中输入文字。

      使用改变元素顺序后,虽然元素被更新,但用户的输入被保留,这是因为元素并没有被重新渲染,而只是部份更新而已。vm.list.reverse()

      使用 Key

      修改上例,每个 都使用 绑定一个属性 并设定唯一值,目的是确保每个元素的唯一性,

      当元素更新,例如改变顺序时,有可识别唯一性的 key 来确保重新渲染。<li>v-bind:key

      <div id="app">
        <ul>
          <li v-for="(item, index) in list" :key="item.id">
            ${ index } <input type="text" :placeholder="item.name" />
          </li>
        </ul>
      </div>
      
      var vm = new Vue({
        el: '#app',
        delimiters: ['${', '}'],
        data: {
          list: [
            { id: '123456789', name: '選項 1' },
            { id: '234567890', name: '選項 2' },
            { id: '345678901', name: '選項 3' },
          ],
        },
      });
      

      按照不更新的那种更改顺序,设定 key 值便会重新更新;

      所有会更改数组的方法

      下面这些方法是会更改数组的,需要记住

      'push',   新增元素。
      'pop',    删除最后一个
      'shift',  删除第一个 (即最旧的) 元素。
      'unshift',加入元素至第一个位置。
      
      'splice', 加入或移除元素。
      'sort',   由小至大排序。
      'reverse' 元素反序排列
      

      显示处理后的结果

      v-for 迭代的数据是使用 computedmethods 处理后的结果。 (不是直接的 Data 数据)

      例如:显示数量大于 6 的水果。

      <div id="app">
        <ul>
          <li v-for="item in filteredFrouts">${ item.name }</li>
        </ul>
      </div>
      
      var vm = new Vue({
        el: '#app',
        delimiters: ['${', '}'],
        data: {
          frouts: [
            {
              name: 'Apple',
              count: 10,
            },
            {
              name: 'Orange',
              count: 5,
            },
            {
              name: 'Banana',
              count: 20,
            },
          ],
        },
        computed: {
          filteredFrouts: function() {
            return this.frouts.filter(function(item) {
              return item.count > 6;
            });
          },
        },
      });
      

      v-for 与 v-if 优先权的比较

      v-for的优先权高于v-if,因此当两者皆出现在同一个元素上时,v-if会随着v-for重覆执行数次。

      如下所示,v-if 会执行 10 次,每次都会判断 n 除以 2 的余数是否为 1,若为 1 则显示,否则就隐藏。

      <ul>
        <li v-if="n % 2 === 1" v-for="n in 10">${ n }</li>
      </ul>
      

      注意,v-for 的个数范围判断条件成立后,才会轮到 v-if 来判断显示与否。

      这是什么意思呢?来看下一个例子就知道了。

      如下所示,这里同时出现了 v-for、v-if 和 v-else 三个指令。

      在这个例子中,我们试图印出 list 阵列的元素内容,而目前 list 是空阵列,没有任何项目可显示。

      因此,当 v-for 在判断 item in list 时,发现条件不成立,就不去做 v-if 和 v-else 判断了,导致原本没有元素印出时应该要提示的「Nothing could show.」都没有出现:(

      <div id="app">
        <div v-if="list.length !== 0" v-for="item in list">
          <div>${ item.name }</div>
        </div>
        <div v-else>
          Nothing could show.
        </div>
      </div>
      
      new Vue({
        el: '#app',
        delimiters: ['${', '}'],
        data: {
          list: [],
        },
      });
      

      总结,由于 v-for 优先权较高,当 v-for 执行完条件判断后,若条件不成立,则后面的 v-if 也不会执行,接着忽略了其后的 v-else。

      解决办法

      解法如下,让 v-for 来判断 list 是否有内容的状况,v-if 只要负责处理项目为 0 个的情况即可。

      <div id="app">
        <div v-for="item in list">
          <div>${ item.name }</div>
        </div>
        <div v-if="list.length === 0">
          Nothing could show.
        </div>
      </div>
      

      参考:https://cythilya.github.io/2017/04/27/vue-list-rendering/

      目录
      目录