一、总结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).length
return 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>