查看整体的效果哈
实现功能:
1、将已有的任务渲染到页面
2、在输入框中输入内容后按enter键,即可把内容添加到下面的列表中(如果内容为空则不添加)
3、动态计算有几个已完成的任务以及所有的任务
4、点击复选框,实现选中或不选中效果(即完成或未完成)
5、删除单个任务以及删除已完成任务
下面这个图是我分析拆分组件的
所拆分的组件有:管理所有的组件App[ Header组件、List组件[Item组件]、Footer组件]
💗 功能一:将已有的任务渲染到页面
我们知道data数据是放到所对应的组件里面,由于功能都需要用到data数据,则将数据放到管理所有子组件的父组件App上面
通过v-for指令将数据渲染到页面
UserList组件
<template> <ul class="todo-main"> <UserItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" > </ul> </template> <script> import UserItem from "./UserItem.vue"; export default { name: "UserList", components: { UserItem }, props: ["todos", "checktodo", "deletetodo"], }; </script>
UserItem组件
<template> <li> <label> <input type="checkbox" :checked="todo.done" /> <span>{{ todo.title }}</span> </label> <button class="btn btn-danger"">删除</button> </li> </template> <script> export default { name: "UserItem", props: ["todo"] }; </script>
💗 功能二: 在输入框中输入内容后按enter键,即可把内容添加到下面的列表中(如果内容为空则不添加)
在UserHeader.vue组件里面为表单绑定一个回车事件,配置一个add事件,添加一个任务
<input
type="text"
placeholder="请输入你的任务名称,按回车键确认"
@keyup.enter="add"
v-model="title"
/>
如何通知App组件去添加一个todo对象 也就是将包装好的todoObj对象传递给App组件?
利用props配置可以实现父组件给子组件传值的操作,此功能需求得实现子组件传值给父组件的操作
因为添加任务的是由UserHeader组件添加数据到UserList组件,而两者的关系是兄弟关系,只有借助它们共同的父组件进行间接传值的操作
思路:父组件提前给子组件传递一个函数,子组件将需要传递给父组件的值通过参数的形式传递
App组件提前给子组件传递一个函数addtodo
<UserHeader :addtodo="addtodo" /> methods: { //添加一个todoObj addtodo(todoObj) { //往data里面添加数据,data数据改变了,重新解析模版 this.todos.unshift(todoObj); },
UserHeader子组件:
随机生成一个唯一的id
安装: npm i nanoid
导入:import {nanoid} from 'nanoid'
使用:id: nanoid()
props: ["addtodo"], methods: { add() { //校验数据 if (!this.title.trim()) { alert("数据不能为空"); } //添加一个信息 也可以直接用e.target.value拿到这个输入的值 // 将用户的输入包装成一个todoObj对象 const todoObj = { id: nanoid(), title: this.title, done: false }; //通知App组件去添加一个todo对象 也就是将包装好的todoObj对象传递给App组件 this.addtodo(todoObj); //清空输入 this.title = " "; }, },
💗 功能三: 动态计算有几个已完成的任务以及所有的任务
此时需要在UserFooter组件中通过计算属性计算得出已完成的任务
computed: {
doneTotal() {
return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0);
},
},
arry.reduce()方法:
reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。
第一个参数:累计器累计回调的返回值; 它是上一次调用回调时返回的累积值
第二个参数:数组中正在处理的元素。
计算所有的任务
方法一:最简单的方法
todos.length
第二种:计算得出
total() {
return this.todos.length;
},
💗 功能四、点击复选框,实现选中或不选中效果(即完成或未完成)双向绑定
借助UserList 组件实现UserItem和App组件之间互相传值
UserItem组件:
<script>
export default {
name: "UserItem",
props: ["todo", "checktodo"],
methods: {
handlechack(id) {
//通知App组件将对应的todo对象的done值取反
this.checktodo(id);
},
},
};
</script>
UserFooter组件:
isAll: {
get() {
//返回的是布尔值
return this.doneTotal === this.total && this.total > 0;
},
set(value) {
this.checkAlltodo(value);
},
},
App 组件:
methods: {
//勾选或者取消勾选一个todo
checktodo(id) {
this.todos.forEach((todo) => {
if (todo.id === id) {
todo.done = !todo.done;
}
});
},
//全选或不全选todoObj
checkAlltodo(done) {
this.todos.forEach((todo) => {
todo.done = done;
});
},
},
💗 功能五、删除单个任务以及删除已完成任务
App.vue 组件
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<!-- 为了让儿子能给父亲传递值,所以父亲准备一个函数接受儿子传递过来的参数 -->
<UserHeader :addtodo="addtodo" />
<UserList
:todos="todos"
:checktodo="checktodo"
:deletetodo="deletetodo"
/>
<UserFooter
:todos="todos"
:checkAlltodo="checkAlltodo"
:clearAlltodo="clearAlltodo"
/>
</div>
</div>
</div>
</template>
methods: {
//删除选中的todoObj
deletetodo(id) {
this.todos = this.todos.filter((todo) => {
//将id不等于当前删除的那个id,的todoObj筛选出来重新渲染
return todo.id !== id;
});
},
//删除已完成
clearAlltodo() {
this.todos = this.todos.filter((todo) => {
return !todo.done;
});
},
},
UserItem.vue组件 - 删除单个任务
<template>
<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
</template>
<script>
export default {
name: "UserItem",
props: ["deletetodo"],
methods: {
handleDelete(id) {
if (confirm("确定删除吗? ")) {
//通知App组件将对应的todo对象删除
this.deletetodo(id);
}
},
},
};
</script>
UserFooter.vue 组件-- 删除已完成任务
methods: {
//删除已完成
clearAll() {
this.clearAlltodo();
},
},
以上就是基于Vue组件实现的一个TodoList 案例,代码不全,但是每个功能都分析了,我相信你是可以哒