使用 Vue 3 + TypeScript + Pinia 的简单项目
以下是一个使用 Vue 3 + TypeScript + Pinia 的简单项目示例,我们将创建一个待办事项(Todo List)应用:
1. 创建项目
bashnpm create vue@latest# 选择 TypeScript 和 Pinia 选项cd your-projectnpm installnpm install pinia @pinia/nuxt
2. 项目结构
/src
/stores
todoStore.ts
/components
TodoList.vue
App.vue
main.ts
3. 创建 Pinia Store (/stores/todoStore.ts)
import { defineStore } from 'pinia'export interface Todo { id: number text: string done: boolean}export const useTodoStore = defineStore('todo', { state: () => ({ todos: [] as Todo[], filter: 'all' as 'all' | 'done' | 'undone' }), actions: { addTodo(text: string) { this.todos.push({ id: Date.now(), text, done: false }) }, toggleTodo(id: number) { const todo = this.todos.find(t => t.id === id) if (todo) { todo.done = !todo.done } }, deleteTodo(id: number) { this.todos = this.todos.filter(t => t.id !== id) } }, getters: { filteredTodos(): Todo[] { switch (this.filter) { case 'done': return this.todos.filter(t => t.done) case 'undone': return this.todos.filter(t => !t.done) default: return this.todos } } }})4. 主组件 (App.vue)
<script setup>import TodoList from './components/TodoList.vue'</script><template> <div> <h1>Todo List</h1> <TodoList /> </div></template><style>.container { max-width: 600px; margin: 0 auto; padding: 20px;}</style>5. TodoList 组件 (/components/TodoList.vue)
<script setup>import { ref } from 'vue'import { useTodoStore } from '../stores/todoStore'import { storeToRefs } from 'pinia'const store = useTodoStore()const { filteredTodos: todos, filter } = storeToRefs(store)const { addTodo, toggleTodo, deleteTodo } = storeconst newTodo = ref('')const handleAdd = () => { if (newTodo.value.trim()) { addTodo(newTodo.value.trim()) newTodo.value = '' }}</script><template> <div> <div> <input v-model="newTodo" @keyup.enter="handleAdd" placeholder="Add new todo..." /> <button @click="handleAdd">Add</button> </div> <div> <button :class="{ active: filter === 'all' }" @click="filter = 'all'" > All </button> <button :class="{ active: filter === 'done' }" @click="filter = 'done'" > Done </button> <button :class="{ active: filter === 'undone' }" @click="filter = 'undone'" > Undone </button> </div> <ul> <li v-for="todo in todos" :key="todo.id"> <input type="checkbox" :checked="todo.done" @change="toggleTodo(todo.id)" /> <span :class="{ done: todo.done }">{{ todo.text }}</span> <button @click="deleteTodo(todo.id)">×</button> </li> </ul> </div></template><style scoped>.todo-item { display: flex; align-items: center; padding: 8px; margin: 5px 0; border: 1px solid #ddd; border-radius: 4px;}.done { text-decoration: line-through; color: #888;}.input-group { margin-bottom: 20px; display: flex; gap: 10px;}input { flex: 1; padding: 8px;}button { padding: 8px 16px; cursor: pointer;}.filters { margin-bottom: 15px; display: flex; gap: 10px;}button.active { background-color: #646cff; color: white;}.delete-btn { margin-left: auto; padding: 0 8px; background: none; border: none; font-size: 1.2em; color: #ff4444;}</style>6. 修改 main.ts
import { createApp } from 'vue'import { createPinia } from 'pinia'import App from './App.vue'const app = createApp(App)const pinia = createPinia()app.use(pinia)app.mount('#app')7. 运行项目
npm run dev
主要功能说明:
使用 Pinia 进行状态管理
支持添加/删除待办事项
切换任务完成状态
过滤显示不同状态的任务
使用 TypeScript 进行类型检查
响应式状态管理
使用 Composition API
这个示例展示了 Vue 3 的组合式 API 与 Pinia 的结合使用,通过 TypeScript 的类型系统增强了代码的可维护性。Pinia 的状态管理逻辑集中在 store 中,组件主要负责 UI 交互和状态展示。
