將 Todo List 以 Vue Router 實現,將更接近實務上的使用。
Todo List
All
Active
Completed
加上以下 3 個 route
/
:name 為all
,component 為TodoList
view/active
:name 為active
,component 為TodoList
view/completed
:name 為completed
,component 為TodoList
view
All
button 改切換/
routeActive
button 改切換/active
buttonCompleted
button 改切換/completed
button
Routes
routes/index.js
import { createRouter, createWebHistory } from 'vue-router'
import TodoView from '../views/TodoView.vue'
export let router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
name: 'all',
component: TodoView
},
{
path: '/active',
name: 'active',
component: TodoView
},
{
path: '/completed',
name: 'completed',
component: TodoView
}
]
})
Line 2
import TodoView from '../views/TodoView.vue'
- 引用
TodoView
view,將在 route 內指定 view
Line 4
export let router = createRouter()
createRouter()
:建立router
object
Line 5
history: createWebHistory(),
createWebHistory()
:Vue Router 使用 HTML 5 Mode
Line 6
routes: [
{
path: '/',
name: 'all',
component: TodoView
},
{
path: '/active',
name: 'active',
component: TodoView
},
{
path: '/completed',
name: 'completed',
component: TodoView
}
]
path
:設定 URLname
:設定 router 邏輯名稱,Vue 內將以此名稱跳轉component
:設定 route 所對應的的 view
App
App.vue
<template>
<RouterView />
</template>
<script setup>
import { RouterView } from 'vue-router'
</script>
Line 2
<RouterView />
<RouterView>
為 Vue Router 內建的 component,Vue Router 將 render 此 component
View
views/TodoView.vue
<template>
<TodoList />
</template>
<script setup>
import TodoList from '@/components/TodoList.vue'
</script>
Line 2
<TodoList />
- 使用
<TodoList>
component
Component
TodoList.vue
<template>
<TodoHeader v-model="newTodo" @addTodo="onAddTodo" />
<TodoMain
:dataSrc="filteredTodos"
@completedTodo="onCompletedTodo"
@saveTodo="onSaveTodo"
@delTodo="onDelTodo"
/>
<TodoFooter
:dataSrc="todos"
@filterAll="onFilterAll"
@filterActive="onFilterActive"
@filterCompleted="onFilterCompleted"
@clearCompleted="onClearCompleted"
>items left
</TodoFooter>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
import TodoHeader from '@/components/TodoHeader.vue'
import TodoMain from '@/components/TodoMain.vue'
import TodoFooter from '@/components/TodoFooter.vue'
import { getTodos, addTodo, saveTodo, delTodo } from '@/api/todos.js'
import { useRoute, useRouter } from 'vue-router'
let route = useRoute()
let { push } = useRouter()
let todos = ref([])
let newTodo = ref('')
let active = computed(() => todos.value.filter((todo) => !todo.isCompleted))
let completed = computed(() => todos.value.filter((todo) => todo.isCompleted))
let filteredTodos = computed(
() =>
({
all: todos.value,
active: active.value,
completed: completed.value
})[route.name]
)
onMounted(async () => (todos.value = await getTodos()))
let onAddTodo = async (val) => {
if (val === '') return
await addTodo(val)
todos.value = await getTodos()
newTodo.value = ''
}
let onCompletedTodo = async (item) => {
await saveTodo(item)
}
let onSaveTodo = async (item) => {
await saveTodo(item)
}
let onDelTodo = async (item) => {
await delTodo(item)
todos.value = await getTodos()
}
let onClearCompleted = async () => {
for (let item of completed.value) {
await delTodo(item)
}
todos.value = await getTodos()
}
let onFilterAll = () => push({ name: 'all' })
let onFilterActive = () => push({ name: 'active' })
let onFilterCompleted = () => push({ name: 'completed' })
</script>
Line 25
import { useRoute, useRouter } from 'vue-router'
- 從 Vue Router 引用
useRoute()
與useRouter()
Line 27
let route = useRoute()
let { push } = useRouter()
useRoute()
:取得目前route
objectuseRouter()
:取得 Vue Router Object,從該 object 取出push()
Line 35
let filteredTodos = computed(
() =>
({
all: todos.value,
active: active.value,
completed: completed.value
})[route.name]
)
- 取得目前
route
object 的name
- 從
name
filter 適當todos
Line 75
let onFilterAll = () => push({ name: 'all' })
let onFilterActive = () => push({ name: 'active' })
let onFilterCompleted = () => push({ name: 'completed' })
<TodoFooter>
component 所傳出的FilterAll
、FilterActive
、FilterCompleted
event 改直接使用push()
切換 route
Conclusion
- 不一定一個 route 就要對應一個 view,也可以多個 route 對應一個 view,只要 route 的 name 不同即可