三部分实现todoList
//todoHeader组件
<template>
<div>
//数据双向绑定,trim去除空格,keyup实现按回车键添加一条todo列表
<input v-model.trim="text" @keyup.enter="addTodo">
<button @click="addTodo">addtodo</button>
</div>
</template>
<script>
export default {
data(){
return{
text:""
}
},
methods:{
addTodo(){
//输入框有内容才能发送
if(this.text){
//自定义一条todo,id为时间戳
let todo={id:+new Date(),text:this.text,completed:false}
//这里使用子组件反向传值修改父组件的值,把自定义的todo传过去
this.$emit("add-todo",todo)
}
//输入完内容再清空输入框
this.text=""
}
}
}
</script>
//todoList组件
<template>
<div>
//动态绑定class,todo处于完成状态时添加completed类名
<div v-for="todo in todos" :key="todo.id" :class="{completed:todo.completed}">
//动态绑定复选框勾选属性,根据todo已完成未完成状态
<input type="checkbox" :checked="todo.completed"
//改变输入内容时自动触发,也是反向传值修改父组件,切换完成状态
@change="$emit('toggle-completed',todo.id)"/>
{{todo.text}}
//删除一条todo,同样反向传值
<button @click="$emit('remove-todo',todo.id)">删除</button>
</div>
</div>
</template>
<script>
export default {
//接受父组件传递过来的todos列表
props:["todos"],
}
</script>
<style scoped>
.completed{
color:#ccc;
text-decoration: line-through;
}
</style>
//todoFilter组件
<template>
<div class="filter-box">
//切换所有todo,未完成todo,已完成todo状态,根据filter的值切换当前状态,点击时候触发的切换也是通过反向传值
<span class="filter-btn" :class="{active:filter===0}" @click="$emit('set-filter',0)">All</span>
<span class="filter-btn" :class="{active:filter===1}" @click="$emit('set-filter',1)">Active</span>
<span class="filter-btn" :class="{active:filter===2}" @click="$emit('set-filter',2)">Completed</span>
</div>
</template>
<script>
export default {
//接受父组件传递过来的filter
props:["filter"]
}
</script>
<style scoped>
.filter-box{
margin-top:10px;
}
.filter-btn{
display:inline-block;
border:1px solid #ccc;
padding:3px;
margin-left:10px;
color:#ccc;
}
.active{
border:1px solid blue;
color:blue;
}
</style>
//App.vue应用主组件
<template>
<div id="app">
//使用组件,并定义自定义事件
<TodoHeader @add-todo="addTodo"></TodoHeader>
//注意,这里之前是:todos="todos",现在换成了计算属性的toggleTodo
<TodoList :todos="toggleTodo" @remove-todo="removeTodo" @toggle-completed="toggleCompleted"></TodoList>
<TodoFilter :filter="filter" @set-filter="setFilter"></TodoFilter>
</div>
</template>
<script>
//引入三个组件
import TodoList from "./components/TodoList"
import TodoHeader from "./components/TodoHeader"
import TodoFilter from "./components/TodoFilter"
export default {
data(){
return{
//存储todos原数据
todos:[
{id:0,text:"好好学习",completed:true},
{id:1,text:"天天向上",completed:true},
{id:2,text:"热爱生活",completed:false},
{id:3,text:"酷爱运动",completed:true},
],
//定义filter初始值
filter:0
}
},
computed:{
//使用计算属性来监听todo状态变化,达到切换所有todo的所有,未完成和已完成状态
toggleTodo(){
return this.todos.filter(todo => {
//当filter为1的时候就是展示未完成的todo
if(this.filter === 1){
return !todo.completed
}
//filter为2的时候展示已完成的todo
if(this.filter === 2){
return todo.completed
}
//默认展示所有的todo
return true
})
}
},
methods:{
//添加一条todo方法
addTodo(todo){
this.todos.push(todo)
},
//切换todo的已完成未完成状态
toggleCompleted(id){
//map修改数组的一项或多项
this.todos=this.todos.map(todo => {
//如果todo.id等于传进来的id就修改
if(todo.id === id){
//保留原todo,修改todo状态
return {...todo,completed:!todo.completed}
}
return todo
})
},
//删除一条todo
removeTodo(id){
//filter过滤,实现删除功能,把当前点击的id相等的todo删掉
this.todos=this.todos.filter(todo => todo.id != id)
},
//设置filter的值为当前传递的值
setFilter(filter){
this.filter = filter
}
},
components:{
//注册组件
TodoList,
TodoHeader,
TodoFilter
},
}
</script>
<style>
</style>
以下为效果图