keyboard_tabSkip to content
listVue Firebase Masterclass

Workshop ประจำหัวข้อนี้

สารบัญ

ตัวอย่าง Book List

เราจะมาลองใช้ Vue router และ Pinia แบบจัดเต็มมากขึ้น โดย

  • เราจะทำ Web ทั้งหมด 3 หน้าคือ BookListView, BookEditView, BookCreateView
├── src
    ├── App.vue
    ├── router
       └── index.js
    ├── stores
       └── book.js --> เปลี่ยนเป็น book store
    └── views
        ├── BookListView.vue
        └── BookUpdateView.vue

ที่ stores/books.js

  • สร้าง books สำหรับเก็บ list หนังสือทั้งหมดอออกมา
  • สร้าง method มาทั้งหมด 3 อันคือ
    • addBook สำหรับเพ่ิมหนังสือ
    • updateBook สำหรับอัพเดทหนังสือ
    • removeBook สำหรับลบหนังสือ
javascript
import { defineStore } from 'pinia'

export const useBookStore = defineStore('book', {
  state: () => ({
    books: []
  }),
  actions: {
    addBook (book) {
      this.books.push(book)
    },
    updateBook (book, index) {
      this.books.splice(index, 1, book)
    },
    removeBook (index) {
      this.books.splice(index, 1)
    }
  }
})

ที่ routers/index.js

  • สร้างหน้ามาทั้งหมด 3 หน้าคือ
    • หน้า list หนังสือ (ใช้ BookListView)
    • หน้า add หนังสือ (ใช้ BookUpdateView)
    • หน้า edit หนังสือ (ใช้ BookUpdateView ตัวเดียวกัน)
javascript
import { createRouter, createWebHistory } from 'vue-router'

import BookListView from '../views/BookListView.vue'
import BookUpdateView from '../views/BookUpdateView.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'book-list-view',
      component: BookListView
    },
    {
      path: '/book/create',
      name: 'book-create-view',
      component: BookUpdateView
    },
    {
      path: '/book/update/:id',
      name: 'book-update-view',
      component: BookUpdateView
    }
  ]
})

export default router

ที่ views/BookListView.vue

  • หน้าหลักสำหรับแสดงหนังสือทั้งหมดออกมา
  • ในหน้านี้จะเพิ่มปุ่มเพื่อไปหน้า add book
  • และใน list แต่ละหนังสือจะเพิ่ม edit book (สำหรับแก้ไขข้อมูล) และ remove book (สำหรับลบหนังสือ)
html
<script setup>
import { RouterLink } from 'vue-router'
import { useBookStore } from '../stores/book'

const bookStore = useBookStore()

</script>

<template>
  <div>
    Book List view

    <RouterLink :to="{ name: 'book-create-view' }">
      <button>Add new book</button>
    </RouterLink>

    <ul>
      <li v-for="(book, index) in bookStore.books" :key="book">
        ({{ index }}) {{ book.name }} by {{ book.author }}
        <RouterLink :to="{ name: 'book-update-view', params: { id: index } }">
          <button>Edit</button>
        </RouterLink>
        <button @click="bookStore.removeBook(index)">Delete</button>
      </li>
    </ul>
  </div>
</template>

ที่ views/BookUpdateView.vue

  • ที่หน้านี้เราจะทำ 2 อย่างคือ เพิ่มหนังสือ (addBook) และ อัพเดทข้อมูลหนังสือ (updateBook)
  • โดยเราจะแยกออกด้วยตัวแปร mode โดย check จาก route name ว่า route name ชื่อว่าอะไร
html
<script setup>
import { onMounted, ref, reactive } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useBookStore } from '../stores/book'

const bookStore = useBookStore()
const route = useRoute()
const router = useRouter()

const mode = ref('')
const bookData = reactive({
  name: '',
  author: ''
})
const bookIndex = ref(-1)

const updateBook = () => {
  if (mode.value === 'create') {
    bookStore.addBook(bookData)
  } else {
    bookStore.updateBook(bookData, bookIndex.value)
  }
  router.push({ name: 'book-list-view' })
}

onMounted(() => {
  if (route.params.id) {
    bookIndex.value = parseInt(route.params.id)
    const cBookData = bookStore.books[bookIndex.value]
    bookData.name = cBookData.name
    bookData.author = cBookData.author
  }
  if (route.name === 'book-create-view') {
    mode.value = 'create'
  } else {
    mode.value = 'update'
  }
})

</script>

<template>
  <div>
    Book {{ mode }} view
    <div>
      <div>Book Name</div>
      <input type="text" v-model="bookData.name">
      <div>Book Author</div>
      <input type="text" v-model="bookData.author">
      <div class="action">
        <button @click="updateBook()">
          {{ mode }} book
        </button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.action {
  margin-top: 10px;
}
</style>

และนี่คือผลลัพธ์ทั้งหมดของ workshop

workshop-01