iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 4
1
自我挑戰組

跟 VueJS 認識的30天系列 第 7

[DAY07]跟 Vue.js 認識的30天 - Vue 的列表渲染

v-for 就是 JavaScript 裡的迴圈,基於一組資料來製作相同元素區塊。
先簡單講一下 JavaScript 裡 for...infor...of 的使用方法及差別。

for...in
主要是為遍歷物件屬性。

const obj = {a:1, b:2, c:3}
for(const prop in obj){
  // prop 是物件屬性名
  console.log(prop) //a b c
  console.log(obj[prop]) // 1 2 3
}

for...of
用於可迭代物件,如字串、陣列、DOM NodeList 等等。

const arr =  ['a', 'b', 'c']
for(const value of arr){
   // value 是陣列值
  console.log(value) //a b c
}

MDN - for...in

MDN - for...of

v-for 指令

迭代陣列

僅有值

<!--item是從items代入的資料(從索引值0開始一筆一筆的代入)-->
<div v-for="item in items">{{ item.type }}</div>

放入索引值

<!--item是從items代入的資料(從索引值0開始一筆一筆的代入),index是代入資料(item)的索引值-->
<div v-for="(item,index) in items">{{ index }}-{{ item.type }}</div>

整體架構會如下:

<div id="vm">
  <div v-for="(item,index) in items">{{ index }}-{{ item.type }}</div>
</div>
<script>
  const vm = new Vue({
    el:'#vm',
    data:{
      items:[{type: 'apple', made: 'USA'},{type: 'oppo', made: 'China'}]
    }
  })
</script>

對於陣列資料的渲染,更推薦使用 v-for="item of items" ,因為在 JS 中 for...offor...in 更適合用在迭代中,因此使用 v-for="item of items" 會更接近 JS 的語法。

迭代物件

<!--value是物件屬性值,key是物件屬性名,而index是指該key-value pair 是第幾筆資料-->
<div v-for="(value,key,index) in obj">{{ key }}-{{ value }}</div>

渲染出來的結果跟迭代陣列很像。

v-for 指令來迭代數字

<div v-for="num in 10">{{ num }}</div>

須注意 num 的值是從 1 開始。

解決 v-for 元素複用

v-forv-if 有相同的問題, Vue 為了更快速的渲染畫面,在資料改變的狀況下,不會移動已經被渲染過的 DOM ,而是直接更新資料(把已經存在的 DOM 元素資料修改成新的值)。

所以可以透過在 HTML 中使用 v-for 的元素加入 key Attribute(值須為唯一,類似 id ),通知 Vue 這個部分資料如果改變,對於已經存在的元素是需要重新排序或是重用一個元素的。

<!--有key Attribute-->
<div v-for="(user,index) of users">
  <label>{{user.label}}</label>
  <input :placeholder="user.placeholder" :key="user.label">
</div>

可以參考 Demo :[DAY07]跟 Vue.js 認識的30天 - Vue 的列表渲染 比較差別。

渲染過濾後陣列結果的資料

當需要一個經過濾後的陣列去渲染時,可以創建 computed 去執行過濾,再透過 v-for 渲染對 computed 執行結果去做渲染。

<!--對oddNums的值做渲染-->
<div v-for="odd in oddNums">{{ odd }}</div>

<script>
const vm = new Vue({
  el:'#vm',
  data:{
    numbers: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
  },
  computed:{
    oddNums(){
      // 返回 [1, 3, 5, 7, 9]
      return this.numbers.filter(num => num%2 === 1)
    }
  }
})
</script>

利用 templatev-for 做分組

使用到現在,覺得 template 做分組的最大好處真的是減少 <div> 標籤的出現。

<template v-for="item in items">
  <h3>{{ item.type }}</h3>
  <p>{{ item.made }}</p>
</template>

陣列更新如何是響應

在 Vue 文件中有說明,只有 push()pop()shift()unshift()splice()sort()reverse() 等 Vue 會知道陣列有變動。

所以當使用 array[index] 執行更新時,是沒辦法觸發頁面更新的。

const vm = new Vue({
    el:'#vm',
    data:{
      numbers: [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
    },
    methods:{
      changeNum(){
        // 網頁不會更新
        this.numbers[2] = 13
        this.numbers[10] = 11
        // 網頁會更新
        // this.numbers.splice(2,1,13)
        // this.numbers.push(11)
        // this.numbers = [...this.numbers,11]
      }
    }
  })

v-forv-if 不要同時出現在同一個元素上

在 Vue 執行的過程中, v-for 的層級較高,所以會在執行完 v-for 才去執行 v-if 的判斷,也因此會造成 v-for 跑完後,才去一個一個執行判斷,之後決定不執行,這是非常多此一舉的。
如果真的需要 v-forv-if 一起使用的話,建議可以在 v-for 外層(可以是 template )元素上加上 v-if ,先跑完判斷,再決定是否要迭代。

<!--當show是truthy時,下面迭代才會執行-->
<template v-if="show">
  <div v-for="item in items">
    <h3>{{ item.type }}</h3>
    <p>{{ item.made }}</p>
  </div>
</template>
<!--不建議使用下面的做法-->
<!--會先跑迭代,才執行判斷-->
<div v-for="item in items" v-if="show">
  <h3>{{ item.type }}</h3>
  <p>{{ item.made }}</p>
</div>

Demo:[DAY07]跟 Vue.js 認識的30天 - Vue 的列表渲染

參考資料:
Vue.js - v-for

Yes


上一篇
[DAY06]跟 Vue.js 認識的30天 - Vue 的條件渲染
下一篇
[DAY08]跟 Vue.js 認識的3天 - Vue 的事件監聽
系列文
跟 VueJS 認識的30天21
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言