Vue TodoList案例
一、总结TodoList案例
组件化编码流程:
(1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。
(2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:
(1.一个组件在用:放在组件自身即可。
(2. 一些组件在用:放在他们共同的父组件上(状态提升)。
(3).实现交互:从绑定事件开始。
props适用于:
(1).父组件 ==> 子组件 通信
(2).子组件 ==> 父组件 通信(要求父先给子一个函数)
使用v-model时要切记:v-model绑定的值不能是props传过来的值,因为props是不可以修改的!
props传过来的若是对象类型的值,修改对象中的属性时Vue不会报错,但不推荐这样做。
二、Components
1.App.vue:
<template><div class="add-todo"><input class="add-input" v-model="todo" @keydown.enter="loseFocus" ref="addInput" @blur="add"></div>
</template><script>
import { nanoid } from 'nanoid'export default {name:'Add',data() {return {todo:'',}},props:['addTodo'],methods:{loseFocus(){this.$refs.addInput.blur()},add(){const todoObj = {id:nanoid(),text:this.todo,is_check:false}this.addTodo(todoObj)this.todo=''},}}
</script><style scoped lang="less">.add-todo{padding-bottom: 10px;}.add-input {width: 350px;height: 40px;padding: 0 10px;font-size: 16px;border: 1px solid #000;border-radius: 4px;}
</style>
2.allTodo.vue:
<template><div class="all-todo" v-show="todoList.length"><input type="checkbox" v-model="allCompeled"> <!-- <input type="checkbox" @change="toggleTodoAll" :checked="allCompeled"> --><span>已完成{{ finish }}/全部{{ todoList.length }}</span><!-- <button class="todo-item-delete" :style="{'display': show}" @click="todoDelete">清除已完成</button> --><button class="todo-item-delete" v-show="show" @click="todoDelete">清除已完成</button></div>
</template><script>export default {name:'allTodo',props:['todoList','allTodoDelete','toggleAll'],computed:{allCompeled:{get(){return this.todoList.length > 0 && this.todoList.every(item => item.is_check)},set(value){this.toggleAll(value)}},finish(){// return this.todoList.filter(item => item.is_check).lengthreturn this.todoList.reduce((pre,current) => pre+(current.is_check?1:0),0)},show(){return this.finish>0 // return this.finish>0 ? 'block' : 'none'}},methods: {// toggleTodoAll(e){// console.log(e.target.checked)// this.toggleAll(e.target.checked)// },todoDelete(){this.allTodoDelete()}},}
</script><style scoped lang="less">.all-todo{display: flex;height: 30px;padding-top: 10px;}.todo-item-delete{// display: none;height: 30px;background-color: red;color: #fff;border-radius: 4px;cursor: pointer;margin-left: auto;border: none;&:hover {background-color: #f5222d;}}
</style>
3.todoList.vue:
<template><div class="todo-list"><todoItem class="todo-item" v-for="(item) in todoList" :key="item.id" :item="item" :todoDelete="todoDelete":itemCheckChange="itemCheckChange"/></div>
</template><script>import todoItem from './todoItem.vue';export default {name:'todoList',props:['todoList','todoDelete','itemCheckChange'],components:{todoItem}}
</script><style scoped>.todo-list{width: 350px;display: flex;flex-direction: column;border: 1px solid #ccc;border-radius: 4px;overflow: hidden; /* 防止边框圆角被内容覆盖 */padding: 0 10px;}
</style>
4.todoItem.vue:
<template><div ><!-- <input type="checkbox" v-model="item.is_check"> --><input type="checkbox" :checked="item.is_check" @change="checkChange(item.id)"><span>{{ item.text }}</span><button class="todo-item-delete" @click="todosDelete(item.id)">删除</button></div>
</template><script>export default {name:'todoItem',props:['item','todoDelete','itemCheckChange'],methods: {todosDelete(id){this.todoDelete(id)},checkChange(id){this.itemCheckChange(id)}},}
</script><style scoped lang="less">.todo-item{height: 30px;display: flex;align-items: center;padding: 10px 15px;border-bottom: 1px solid #eee;&:hover {background-color: #e8e8e8;.todo-item-delete {display: block;}}}.todo-item-delete{display: none;height: 30px;background-color: red;color: #fff;border-radius: 4px;cursor: pointer;margin-left: auto;border: none;&:hover {background-color: #f5222d;}}.todo-item:last-child {border-bottom: none;}
</style>
5.App.vue:
<template><div class="centent"><Add :todoList="todoList" :addTodo="addTodo"/><todoList :todoList="todoList" :todoDelete="todoDelete" :itemCheckChange="itemCheckChange"/><allTodo :todoList="todoList" :allTodoDelete="allTodoDelete":toggleAll="toggleAll"/></div>
</template><script>import Add from './Components/Add.vue'import todoList from './Components/todoList.vue';import {nanoid} from 'nanoid'import allTodo from './Components/allTodo.vue';export default {name:'App',data() {return {todoList:[{id:nanoid(),text:'test',is_check:false}]}},components:{Add,todoList,allTodo},methods:{addTodo(x){if(x.text.trim()){this.todoList.unshift(x)}},allTodoDelete(){this.todoList = this.todoList.filter(item => !item.is_check)},todoDelete(id){this.todoList = this.todoList.filter(item=>item.id!=id)},itemCheckChange(id){this.todoList.forEach(item=>{if(item.id === id) item.is_check =!item.is_check})},toggleAll(value){this.todoList.forEach(item => {item.is_check=value})}},}
</script><style scoped>.centent{width: 400px;margin: auto;border: 1px solid #000;min-height: 50px;padding: 20px;}
</style>