Skip to main content

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 สำหรับลบหนังสือ
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 ตัวเดียวกัน)
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 (สำหรับลบหนังสือ)
<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 ชื่อว่าอะไร
<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