前言
todolist案例在学习很多技术上都很适合新手练手。在这篇文章中将用Vue技术来实现该案例。此外感兴趣的小伙伴可以点击下方链接来获取案例源码哦!案例源码
链接:https://github.com/lingjing-wq/Vue-todolist
案例效果展示
案例功能介绍
- 任务的添加
- 任务的删除
- 任务的数量统计(已完成、总数量)
- 任务的状态切换(打钩or不打勾)
- 清除所用已完成的任务
- 任务的全选
案例主要技术
- Vue脚手架
- 模块化
- props的应用
- 组件通信
- Vue常用指令(v-for、v-bind、v-show等)
- Vue事件处理
- 计算属性
案例搭建过程
1. 首先使用脚手架新建项目
Vue create vue_test01
2. 切换到vue_test01文件夹下,并启动项目
cd vue_test01
npm run serve
3. 组件化案例
原则是根据案例的功能点来进行拆分。如下
将案例的骨架搭建好
4. 具体代码的实现
App.vue文件
<template>
<div id="app">
<div class="todo-container">
<div class="todo-wrap">
<MyHeader :receive="receive" />
<MyList :todos="todos" :checkTodo="checkTodo" :deleteTodo="deleteTodo" />
<MyFooter :todos="todos" :checkAllTodo='checkAllTodo' :clearAllTodo='clearAllTodo' />
</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: {
//往对象数组中添加新的对象数据
receive(e) {
// console.log("收到数据了",e);
this.todos.unshift(e);
//勾选or取消勾选
},
//勾选or取消勾选
checkTodo(id) {
this.todos.forEach((todo) => {
if (todo.id === id)
todo.done = !todo.done;
})
},
//删除
deleteTodo(id) {
this.todos = this.todos.filter((todo) => {
return todo.id !== id;
})
},
//全选or全不选
checkAllTodo(done) {
this.todos.forEach((todo) => {
todo.done = done;
})
},
//清除所有已完成的任务
clearAllTodo() {
this.todos = this.todos.filter((todo) => {
return !todo.done
})
}
},
}
</script>
MyHeader.vue文件
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add" />
</div>
</template>
<script>
import { nanoid } from 'nanoid'
export default {
name: 'MyHeader',
//接收从APP内传来的函数receive
props:['receive'],
methods: {
add(event) {
// console.log(event.target.value)
if(!event.target.value.trim()) return;//校验数据:输入不为空 & trim()去掉前后空格
//将用户的输入包包装成一个todo对象
const todoObj = { id: nanoid(), title: event.target.value, done: false }
// console.log(todoObj)
this.receive(todoObj);//将需要添加的数据传给App
//添加完后将值置为空
event.target.value=''
}
},
}
</script>
MyList.vue文件
<template>
<ul class="todo-main">
<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" :checkTodo="checkTodo" :deleteTodo="deleteTodo"/>
</ul>
</template>
<script>
import MyItem from './MyItem.vue'
export default {
name: 'MyList',
components: {
MyItem
},
//接收从App组件中来的数据
props:['todos','checkTodo','deleteTodo']
}
</script>
MyItem.vue文件
<template>
<li>
<label>
<input type="checkbox" :checked="todo.done" @click="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'],//接收从MyList组件中传来的数据
methods: {
handleCheck(id) {
// console.log(id)
//通知APP组件将对应的todo对象的done值取反
this.checkTodo(id)
},
//删除
handledelete(id) {
if(confirm('确定删除吗?')){
// console.log(id);
this.deleteTodo(id);
}
}
},
}
</script>
MyFooter.vue文件
<template>
<div class="todo-footer" v-show="todos.length">
<label>
<input type="checkbox" @change='checkAll'/>
</label>
<span>
<span>已完成{{doneTotal}}</span> / 全部{{todos.length}}
</span>
<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
</div>
</template>
<script>
export default {
name: 'MyFooter',
props:['todos','checkAllTodo','clearAllTodo'],
computed:{
doneTotal(){
//计已完成的个数
let i=0;
this.todos.forEach((todo) => {
if(todo.done)
i++;
});
return i;
}
},
methods:{
checkAll(e){
// console.log(e.target.checked)
this.checkAllTodo(e.target.checked);
},
clearAll(){
this.clearAllTodo();
}
},
}
</script>
案例总结
1.组件化编码流程:
(1). 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突.
(2). 实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
1). 一个组件在用:放在组件自身即可.
2).一些组件在用:放在他们共同的父组件上(状态提升)。
(3). 实现交互:从绑定事件开始.
2.props适用于:
(1). 父组件——>子组件 通信
(2).子组件——>父组件通信(要求父先给子一个函数)
注意:
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
3.使用v-model时要切记:
v-model绑定的值不能是props传过来的值,因为props是不可以修改的!