前言

最近学习了Vue,跟着教程完成了一个简单的demo—todoList清单,功能主要有添加、删除待办事件,统计已完成的事件数,一键清空列表等,运用了组件化的编码流程,巩固了父子组件传值的知识点

最终得到的效果如下

一、静态页面

根据功能拆分页面,项目的组织结构如下

App.vue文件

输入框部分拆分为头部组件 MyHeader.vue文件

事件列表的每一行拆分为一个组件,因为每一行的结构相同,如果有多行,就可以在其父组件里面通过 v-for 指令遍历 MyItem.vue文件

事件列表拆分为一个组件,作为MyItem.vue组件的父组件 MyList.vue文件

底部统计与全选功能部分拆分为一个组件 MyFooter.vue文件

效果图如下

二、绑定动态数据

1、数据存储的方式

一堆要做的事情是一个数组,一个个要做的事情是对象。因此可以使用数组来存储多个要做的事情,每个事情是一个对象,包含属性id(标识)、title(名称)、done(是否完成)。

因为在MyList.vue组件中展示数据,所以该数组写在MyList文件中。

data(){

return{

todos:[

{id:'001',title:'吃饭',done:true},

{id:'002',title:'写代码',done:false},

{id:'003',title:'看电视',done:false}

]

}

}

2、数据展示方式

因为存储事情的数组todos在MyList中,而每一个事情todoObj在MyItem中展示,所以需要把每一个事情传递到MyItem文件中,相当于父组件给子组件传值,用到props。

MyList文件中 使用 v-for 遍历todos数组, :todo=“todoObj” 将每一个事情传到MyItem组件

MyItem文件中 使用props接收父组件传递的数据 props:[‘todo’],接收父组件传递的每一个todoObj,注意是 todo

MyList文件修改为

MyHeader文件修改为

4、勾选或取消勾选

涉及多层组件传值:App—>MyList —>MyItem

App文件中添加方法

// 勾选或取消勾选

checkTodo(id){

this.todos.forEach((todo)=>{

if(todo.id === id)

todo.done = !todo.done;

})

}

传给MyList

MyList中用props接收后再传给MyItem,MyItem接收

methods:{

handleTodo(id){

this.checkTodo(id);//调用父组件传递的checkTodo方法

}

}

详细代码,后面附上。

5、删除事件

控制删除按钮显示与隐藏的css代码

li button{

float: right;

display: none;

margin-top: 3px;

}

li:hover button{

display: block;// 控制删除按钮显示(鼠标悬浮在该li上)与隐藏

}

类似于勾选或取消勾选,都是多层组件传值。

App文件中添加方法

// 删除一个事件

deleteTodo(id){

// filter方法会生成一个新数组,所以需要重新给todos赋值

this.todos = this.todos.filter((todo) => {

return todo.id !== id;// 等于该id的会被过滤掉

})

}

将deleteTodo方法先传给MyList文件,在从MyList文件传到MyItem文件。

MyItem文件中button绑定click事件

handleDelete(id){

this.deleteTodo(id);//调用父组件传递的方法

}

6、底部统计

分为两部分

(1)统计已完成的事件数和事件总数

使用计算属性computed完成

已完成{{doneTotal}} / 全部{{total}}

computed:{

doneTotal(){

// 方法1,使用计数器

/*let cnt = 0;

this.todos.forEach(todo =>{

if(todo.done)cnt++;

})

return cnt;*/

// 方法2,使用数组reduce方法

return this.todos.reduce((pre,todo)=>{

return pre + (todo.done ? 1:0);

},0)

},

total(){

return this.todos.length;

},

isAll(){

return this.total === this.doneTotal && this.total>0 //保证总数为0时不勾选

}

},

(2)勾选全部

父组件App中传递checkAllTodo方法给MyFooter子组件

// 全选或全不选

checkAllTodo(done){

this.todos.forEach(todo =>{

todo.done=done;

})

},

checkAll(e){

this.checkAllTodo(e.target.checked);//传入的是checked属性,不是value

},

(3)清除已完成的事件

父子组件传函数clearAllTodo

// 删除已完成的所有事件

clearAllTodo(){

this.todos = this.todos.filter(todo =>{

return !todo.done;// 过滤掉done值为true的事件,留下done为false的事件

})

}

clearAll(){

this.clearAllTodo();

}

当没有事件时,显示效果应为

使用v-show控制标签显示与隐藏