可以练习一个基本的增删改查,不用pinia可以更好的练习组件通信
以下是基本结构
app.vue
<script setup lang="ts">
import "./styles/base.css"
import "./styles/index.css"
import TodoHeader from "./components/TodoHeader.vue";
import TodoMain from "./components/TodoMain.vue";
import TodoFooter from "./components/TodoFooter.vue";
import { computed, ref } from "vue";
//定义数据类型
import type { TodoItem, TodoType } from './todo'
// 定义数据
const todos = ref<TodoItem[]>([])
todos.value = JSON.parse(localStorage.getItem('todos')! || '[]')
// todos.value =
// 当前要显示的类型
const type = ref<TodoType>('all')
//修改type的值
const setType = (val:TodoType) => {
type.value = val
}
const saveTodos = () => {
localStorage.setItem("todos", JSON.stringify(todos.value))
}
const hUpdate = (item: TodoItem) => {
// console.log(item)
// 修改对应的数据
const it = todos.value.find(it => it.id === item.id)
// it!: 非空断言
it!.isDone = !(it!.isDone)
saveTodos()
}
const hAdd = (name: string) => {
// 向数组中添加
todos.value.push({
id: Date.now(),
name,
isDone: false
})
saveTodos()
}
// 单个删除
const hDel = (idx:number) => {
todos.value = todos.value.filter(it => it.id !== idx)
saveTodos()
}
// 多个删除
const hDels = () => {
todos.value = todos.value.filter(it => it.isDone === false)
saveTodos()
}
const filterTodos = computed(() => {
if(type.value === 'all'){
return todos.value
} else if(type.value === 'yes'){
return todos.value.filter(it => it.isDone)
} else {
return todos.value.filter(it => !it.isDone)
}
})
</script>
<template>
<section class="todoapp">
<TodoHeader @add="hAdd"></TodoHeader>
<TodoMain @update="hUpdate" :filterTodos="filterTodos" @hDel="hDel"></TodoMain>
<TodoFooter :filterTodos="filterTodos" :type="type" @setType="setType" @hDels="hDels">
</TodoFooter>
</section>
</template>
头部
<script setup lang="ts">
import { ref } from 'vue';
// 定义数据 - 收集用户输入 - 通过抛出事件把数据传递给父组件
const name = ref('')
const emit = defineEmits<{
(e: 'add', name: string): void
}>()
const add = () => {
// 添加
emit('add', name.value)
// 清空内容
name.value = ''
}
</script>
<template >
<header class="header">
<h1>todos</h1>
<input id="toggle-all" class="toggle-all" type="checkbox" >
<label for="toggle-all"></label>
<input
v-model="name"
@keyup.enter="add"
class="new-todo"
placeholder="输入任务名称-回车确认"
autofocus
/>
</header>
</template>
内容区
<script setup lang="ts">
import type { TodoItem } from '@/todo';
// 接收
defineProps<{
// 属性名:类型
filterTodos:TodoItem[]
}>()
const emit = defineEmits<{
(e:'update', item: TodoItem): void
(e:'hDel', idx: number): void
}>()
const hChange = (item: TodoItem) => {
// 抛出事件
emit("update", item)
}
const hDel = (idx: number) => {
// 抛出事件
emit("hDel", idx)
}
</script>
<template>
<ul class="todo-list">
<!-- completed: 完成的类名 -->
<li
v-for="item in filterTodos"
:key="item.id"
:class="{completed: item.isDone}">
<div class="view">
<input
@change="hChange(item)"
:value="item.isDone"
class="toggle" type="checkbox" :checked="item.isDone"/>
<label>{{item.name}}</label>
<button class="destroy" @click="hDel(item.id)"></button>
</div>
</li>
</ul>
</template>
底部
<script setup lang="ts">
import type { TodoItem ,TodoType} from '../todo';
// 接收
const prop = defineProps<{
// 属性名:类型
filterTodos: TodoItem[]
type: TodoType
}>()
//接收父组件方法
const emit = defineEmits<{
(e: 'setType', type: TodoType): void
(e: 'hDels'): void
}>()
//修改type状态值
const setType = (val: TodoType) => {
emit('setType', val)
}
// 删除已完成事项
const hDels = () => {
// 抛出事件
emit("hDels")
}
</script>
<template>
<footer class="footer">
<!-- ?可选链运算符,没有值时不报错 -->
<span class="todo-count">剩余<strong>{{ filterTodos?.length }}</strong></span>
<ul class="filters">
<li>
<a class="selected" href="javascript:;" @click="setType('all')">全部</a>
</li>
<li>
<a href="javascript:;" @click="setType('no')">未完成</a>
</li>
<li>
<a href="javascript:;" @click="setType('yes')">已完成</a>
</li>
</ul>
<button class="clear-completed" @click="hDels">清除已完成</button>
</footer>
</template>
todo.d.ts文件
type TodoItem = {
id: number
name: string
isDone: boolean
}
type TodoType = 'all' | 'no' | 'yes'
export {
TodoItem,
TodoType
}
这些都是 Web 开发中常见的基本技能和概念,通过编写一个待办事项应用程序,可以锻炼这些技能,将它们应用到实际的项目中。编写一个小型应用程序还可以提高你的编码能力、逻辑思维和问题解决能力。