Vue实现简易TodoList
文章目录TodoList案例分析App.vue功能实现:1.Header部分Header.vue2.List部分List.vue3.Item部分Item.vue4.Footer部分Footer.vueTodoList案例(省略样式部分)分析分为四个组件 Header List Item FooterApp.vue<template><div id="root"><di
文章目录
TodoList案例
(省略样式部分)
分析
分为四个组件 Header List Item Footer
App.vue
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<MyHeader :addTodo="addTodo"></MyHeader>
<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></MyList>
<MyFooter :todos="todos" :checkAllTodo="checkAllTodo" :clearAllTodo="clearAllTodo"></MyFooter>
</div>
</div>
</div>
</template>
<script>
import MyHeader from "./components/MyHeader.vue";
import MyList from "./components/MyList.vue";
import MyFooter from "./components/MyFooter.vue";
export default {
name: "App",
components: { MyHeader, MyList, MyFooter },
data() {
return {
todos:[
{id:"001",title:"抽烟",done:true},
{id:"002",title:"喝酒",done:false},
{id:"003",title:"开车",done:true}
]
}
},
methods:{
//添加todo
addTodo(todoObj){
this.todos.unshift(todoObj)
},
//勾选或取消勾选一个todo
checkTodo(id){
//遍历todo
this.todos.forEach((todo)=>{
if(todo.id===id) todo.done=!todo.done
})
},
deleteTodo(id){
this.todos = this.todos.filter((todo)=>{
return todo.id !== id
})
},
//全选或全不选
checkAllTodo(done){
this.todos.forEach((todo)=>{
todo.done = done
})
},
//清除所有已完成todo
clearAllTodo(){
this.todos = this.todos.filter((todo)=>{
return !todo.done
})
}
}
};
</script>
<style></style>
功能实现:
1.Header部分
按回车键后添加内容todoObj,内容应添加进List部分,兄弟间不可传数据,将todos中内容放置在父组件App中,通过子组件Header向父组件App中传递todoObj来实现新内容的添加。
此处涉及子向父传数据,该案例使用最基础的方法,父先向子传入一个函数(addTodo
),子组件通过props数组接收。子组件再调用这个函数实现子向父传递。
Header.vue
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add"/>
</div>
</template>
<script>
import {nanoid} from 'nanoid'
export default {
name:'MyHeader',
data() {
return {
title:''
}
},
props:['addTodo'],
//接收从App传递过来的addTodo
methods: {
add(){
//校验数据
if(!this.title.trim()) return alert('输入不能为空')
//将用户输入生成一个对象
const todoObj={id:nanoid(),title:this.title,done:false}
//将新生成的对象传给App
this.addTodo(todoObj)
this.title=''
}
},
}
</script>
<style scoped></style>
注: 在为新添加的内容生成唯一id时使用nanoid
方法,需要先引入。
2.List部分
将App中todos传给List进行渲染,将todoObj传给Item。
List.vue
<template>
<ul class="todo-main">
<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo" :deleteTodo="deleteTodo"></MyItem>
</ul>
</template>
<script>
import MyItem from './MyItem'
export default {
name:'MyList',
components:{MyItem},
props:['todos','checkTodo','deleteTodo'] //接收
}
</script>
<style scoped></style>
3.Item部分
① 标记勾选或取消勾选一个todo,改变done
的值(通过id:向App组件传id => 子向父传数据),在子组件中勾选或取消勾选 可以通过@change
或@click
调用函数。
需要App组件向该组件传入相应函数(checkTodo
<=> 在App组件中编写的改变done
值的函数),即需要App先向List组件传函数,再由List组件向Item组件传函数。
② 点击删除按钮实现删除某一todo,通过id值确定删除的内容。实现过程与上述类似。
Item.vue
<template>
<li>
<label>
<input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)"/>
<span>{{todo.title}}</span>
</label>
<button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
</li>
</template>
<script>
export default {
name: "MyItem",
//声明接收todo对象
props:['todo','checkTodo','deleteTodo'],
methods: {
//通知App
handleCheck(id){
this.checkTodo(id)
},
handleDelete(id){
if(confirm('确定删除吗?')){
this.deleteTodo(id)
}
}
},
};
</script>
<style scoped></style>
4.Footer部分
① 全部todo数,采用计算属性(即todos数组的长度)
② 已完成todo的个数,采用计算属性,使用数组方法reduce
=> 迭代数组,把它累积到一个值中
reduce(回调函数(pre,current){},初始值)
注: 数组长度是多少 函数调用多少次
初始pre为统计数0,current为正在处理项
例如:
this.todos.reduce((pre,current)=>{ 012
console.log('@',pre) 012
return pre+1 123
},0)
在回调函数中:
-
上一次的返回值为下一次的pre值
-
控制台上输出为012
-
最后一次返回值为3
最后一次返回值3为reduce的返回值
③ 当所有todo被选中时,最下方的复选框也应被勾选。
给该复选框绑定checked
属性,通过计算属性isAll
(布尔型)决定checked值。当 全部todo数和已完成todo个数相等 且 总数>0 为真,被勾选。
④ 当勾选或取消最下方复选框时,上述每个todo的复选框都被勾选或都不选。
将最下方复选框勾选状态即checked
值传给App组件,在App组件中编写 使每个todo的done
值与其checked
值相等 的函数。上述需Footer组件向App组件传数据,实现过程与Item部分中相同(子 => 父)。
⑤ 清除已完成任务按钮的实现。
删除已完成todo项,需在App组件中编写相应函数。与子=>父过程相似。
Footer.vue
<template>
<div class="todo-footer" v-show="total!=0">
<label>
<input type="checkbox" :checked="isAll" @change="checkAll"/>
</label>
<span>
<span>已完成{{doneTotal}}</span> / 全部{{total}}
</span>
<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
</div>
</template>
<script>
export default {
name: "MyFooter",
props: ["todos", "checkAllTodo","clearAllTodo"],
computed: {
total() {
return this.todos.length;
},
doneTotal() {
return this.todos.reduce((pre, todo) => {
return pre + (todo.done ? 1 : 0);
}, 0);
},
isAll() {
return this.total === this.doneTotal && this.total > 0;
},
},
methods: {
checkAll(e) {
this.checkAllTodo(e.target.checked);
},
clearAll(){
this.clearAllTodo();
}
},
};
</script>
<style scoped></style>
注: 使用v-model时,绑定的值不能是props传过来的值,因为props不可修改
更多推荐
所有评论(0)