这个待办事项有以下功能:增删查,既新增待办事项,删除待办事项,查看全部,未完成,完成待办事项,当鼠标移动到待办事项上时会显示删除按钮
分为四个部分来实现:ToDoHeader.vue、ToDoMain.vue、ToDoFooter.vue、ToDoList.vue
ToDoHeader.vue
头部部分
<template><div><div class="header"><p class="title">待办事项</p><input class="new-todo" type="text" placeholder="请填写任务" v-model.trim="name" @keyup.enter="enterName" /></div></div></template><script setup>import {ref} from 'vue'const name = ref('')const emit = defineEmits(['addTodo'])const enterName = () => {// 触发自定义事件,为空时弹出警示框if(name.value===""){alert("任务名称不能为空")return}emit('addTodo', name.value)name.value = ''}</script><style>.title{font-size: 20px;color: red;height: 40px;width: 86.5%;margin: 10px 40px 0 40px;padding-top: 10px;text-align: center;border: 1px solid #ccc;}.new-todo{height: 40px;width: 80%;margin: 5px 40px 0 40px;padding: 4px 0 0 65px;border: 1px solid #ccc;}</style>
ToDoMain.vue
列表总体样式和删除样式
<template><div class="main"><ul class="todo-list"><li v-for="item in list" :key="item.id" :class="{ completed: item.done }"><div class="view"><input class="toggle" type="checkbox" v-model="item.done" /><label>{{ item.name }}</label><button class="destroy" @click="delTodo(item.id)"><div class="overlay">x</div></button></div></li></ul></div>
</template><script setup>//声明propsconst props = defineProps(['list'])//声明自定义事件const emit = defineEmits(['delTodo'])const delTodo = id => {id && emit('delToDo', id) // 触发事件}
</script><style>.view{position: relative;height: 40px;width: 800px;margin-left: 20px;padding-top: 15px;border-bottom: 1px solid #ccc;}li{margin-left: 20px;}label{position: absolute;left: 70px;top: 23px;}.destroy{float: right;border: none;background-color: white;}.overlay{position: absolute;top: 26px;font-size: 40px;color: black;/* 字体居中 */transform: translate(-50%,-50%);font-size: large;/* 悬停前完全透明 */opacity: 0;transition: 0.3s ease-in-out; }.view:hover .overlay{transition: 0.3s ease-in-out;/* 悬停时完全不透明 */opacity: 1;}input[type="checkbox"] {appearance: none;/*取消默认的复选框样式*/width: 30px;/*设置方形宽度为20px*/height: 30px;/*设置方形高度为20px*/border: 1px solid #000;/*设置边框样式*/border-radius: 50%;/*将方形的边框改为圆形*/}input[type="checkbox"]:checked {&:before {content: '\2713';/*添加一个对勾,默认颜色是黑色*/color: greenyellow;/*将对勾颜色改为白色*/font-size: 20px;margin-left: 5px;/*将对勾左边距改为4px,让它看着像居中*/}}
</style>
ToDoList.vue
列表部分
<template><ToDoHeader @addTodo="addTodo"></ToDoHeader><ToDoMain :list="showList" @delToDo="delToDo"></ToDoMain><ToDoFooter :lastLength="lastLength" @updateStatus="updateStatus"></ToDoFooter></template><script setup>import ToDoHeader from './ToDoHeader.vue'import ToDoMain from './ToDoMain.vue'import ToDoFooter from './ToDoFooter.vue'import {computed,ref} from 'vue'const list = ref([{id: 1,name: '跑步',done: false,},{id: 2,name: '健身',done: true,},])const addTodo = name => {list.value.push({name,done: false,id: ~~(Math.random() * 1000)})}const delToDo = id => {list.value = list.value.filter(item => item.id !== id)}const lastLength = computed(() => {return list.value.filter(item => !item.done).length})const status = ref('all')const showList = computed(() => {if (status.value === 'all') {return list.value}else if (status.value === 'active') {return list.value.filter(item => !item.done)}else if (status.value === 'completed') {return list.value.filter(item => item.done)}})const updateStatus = setStatus => {status.value = setStatus // 将子组件的状态赋值给父组件}</script><style></style>
ToDoFooter.vue
页脚部分
<template><div class="footer"><span class="todo-count">共<strong>{{ lastLength }}</strong>条未完成任务</span><ul class="filters"><li class="oneli"><a @click.prevent="emit('updateStatus', 'all')" :class="{ selected: status === 'all' }"href="#/">全部</a></li><li><a @click.prevent="emit('updateStatus', 'active')" :class="{ selected: status === 'active' }"href="#/active">未完成</a></li><li><a @click.prevent="emit('updateStatus', 'completed')" :class="{ selected: status === 'completed' }"href="#/completed">已完成</a></li></ul></div>
</template><script setup>const emit = defineEmits(['updateStatus'])const props = defineProps(['lastLength', 'status'])
</script><style>.oneli{margin-left: 50%;}.todo-count {margin-left: 40px;float: left;}ul {margin-left: -25px;list-style-type: none;}li {float: left;margin-left: 4px;}a {border: 1px solid #d3d3d3;/* 清除a标签默认效果 */text-decoration: none;color: black;font-size: 8px;}
</style>
最后更改main.js中的代码
main.js
import { createApp } from 'vue'
import App from './components/ToDoList.vue'createApp(App).mount('#app')
总体效果:
新增效果:
删除效果:
鼠标悬停时会显示删除按钮
查找效果:
全部效果:
未完成效果:
完成效果: