Vue.js เริ่มต้น ตอน9 (List Rendering v-for)

Jun 11, 2018 21:01 · 449 words · 3 minute read vue.js JavaScript

ในบทความนี้เราจะมาเรียนรู้การวนลูปแสดงข้อมูลในลักษณะ List ซึ่ง Vue ก็มีเครื่องมือมาให้เราใช้งานได้อย่างง่ายดาย ก็คือ v-for มันสามารถใช้งานได้ทั้ง Array และ Object มาดูตัวอย่างแรกกันเลย

v-for กับข้อมูล Array

Template:

<ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>

Data:

data: {
  items: [
    { message: 'Foo' },
    { message: 'Bar' }
  ]
}

จะได้ผลลัพธ์

ในตัวอย่างเราจะใช้ v-for=“item in items” ลูปแสดงผลข้อมูลที่อยู่ใน items ได้เลย นอกจากนี้เรายังสามารถดึงค่า index ของข้อมูลในแต่ละ item ออกมาได้โดยเขียนตามตัวอย่างนี้ Template:

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>

Data:

data: {
  parentMessage: 'Parent',
  items: [
    { message: 'Foo' },
    { message: 'Bar' }
  ]
}

ผลลัพธ์

v-for กับข้อมูล Object

v-for สามารถใช่กับ Object ได้ด้วยเหมือนกัน โดยมีรูปแบบการใช้งานดังตัวอย่างนี้ Template:

<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>

Data:

data: {
  object: {
    firstName: 'John',
    lastName: 'Doe',
    age: 30
  }
}

ผลลัพธ์

และยังสามารถดึงข้อมูลของ Key ในแต่ละ item ออกมาได้อีกด้วย ดังตัวอย่าง

<div v-for="(value, key) in object">
  {{ key }}: {{ value }}
</div>

หรือ Index ของแต่ละ key ก็ยังสามารถดึงออกมาได้ ตามนตัวอย่างนี้

<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }}: {{ value }}
</div>

เรื่องของ Key กับ v-for

เมื่อคุณใช้งาน v-for แล้วเมื่อข้อมูลมีการเปลี่ยนแปลงลําดับใหม่ v-for จะใช้การแทนที่ของข้อมูลแทนการย้าย Dom อาจทําให้ข้อมูลอาจจะแสดงผิดพลาด เช่นข้อมูลแสดงซํ้า สิ่งที่ควรทําคือการกําหนด Key ที่ไม่ซํ้ากัน ให้กับ HTML ในแต่ละ Item เพื่อให้ Vue แยกแยะแต่ละ node ได้ มาดูตัวอย่างการใช้ Key กันครับ

<div v-for="item in items" :key="item.id">
  <!-- content -->
</div>

Array Change Detection

ในกรณีที่ใช้ v-for กับ Array เราจะมาดูกันว่า การเปลี่ยนแปลงใดบ้างที่จะทําให้ v-for Render Component บ้าง

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

v-for จะไม่ Render component ใหม่ในกรณีดังต่อไปนี้

  • แก้ไขข้อมูลในบาง item เช่น items[indexOfItem] = newValue
  • เปลี่ยนขนาดของ Array เช่น items.length = newLength

ตามตัวอย่างนี้

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // is NOT reactive
vm.items.length = 2 // is NOT reactive

แต่เราสามารถทําแบบนี้เพื่อให้ข้อมูลอัพเดทได้

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

หรือ

// Array.prototype.splice
this.items.splice(indexOfItem, 1, newValue)

หรือ

this.$set(this.items, indexOfItem, newValue)

หรือเปลี่ยนขนาดได้โดย

this.items.splice(newLength)

Object Change Detection Caveats

ในส่วนของ Object Vue จะไม่ Detect ในกรณีที่เราเพิ่ม Key ของ Object เข้าไปตรงๆ ตามตัวอย่างนี้

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` is now reactive

vm.b = 2
// `vm.b` is NOT reactive

แต่เรายังสามารถเพิ่มได้ด้วยการใช้ set ตามตัวอย่างนี้

var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})
Vue.set(vm.userProfile, 'age', 27)

หรือ

this.$set(this.userProfile, 'age', 27)

Displaying Filtered/Sorted Results

ในบางครั้งเราต้องการแสดงผลของ List แบบเรียงลําดับ หรือมีการ Filter ข้อมูล แต่ไม่ต้องการเปลี่ยน Original Data เราสามารถใช้ Computed มาช่วยได้ตามตัวอย่างนี้ Template:

<li v-for="n in evenNumbers">{{ n }}</li>

script:

data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

v-for with a Range

เราสามารถกําหนดจํานวนการวนลูปแบบนี้ได้ครับ

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

ผลลัพธ์

v-for with v-if

ถ้าในบางกรณีที่เราต้องการแสดงแค่บาง item เท่านั้น เราสามารถใส่เงื่อนไขเข้าไปได้เช่น

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

มาถึงตอนนี้เราสามารถใช้งาน v-for ในรูแปบต่างๆกันไปแล้ว ทั้งในเรื่องของการใช้ v-for กับ Array หรือใช้ กับ Object และเงื่อนไขของการ Update ในแบบต่างๆ หวังว่าเพื่อนๆจะสามารถนําไปประยุกต์ใช้งานได้ไม่ยากครับ