1.组件化编码流程
(1)拆分静态组件:组件要按照功能点拆分,命名不要与 html 元素冲突
(2)实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用
a.一个组件在用,放在组件自身即可
b.一些组件在用:放在他们共同的父组件上()
(3)实现交互:从绑定事件开始
2.props 适用于:
(1)父组件 ==> 子组件 通信
(2)子组件 ==> 父组件 通信(要求先给子一个函数)
3.使用 v-model 时要切记:v-model 绑定的值不能是 props 传过来的值,因为 props 是不可以修改的
4.props 传过来的若是对象类型的值,修改对象中的属性时 Vue 不会报错,但不推荐这样做
e77a0010f82ea8861182a5b39fb115b.png
App.vue
<template>
<div id="root">
<div class="todo-container">
<div class="todo-wrap">
<MyHeader :addTodo="addTodo" />
<MyList
:todos="todos"
:changeTodo="changeTodo"
:deleteTodo="deleteTodo"
/>
<MyFooter
:todos="todos"
:checkAllTodo="checkAllTodo"
:clearAllTodo="clearAllTodo"
/>
</div>
</div>
</div>
</template>
<script>
// 引入组件
import MyHeader from './components/MyHeader'
import MyList from './components/MyList'
import MyFooter from './components/MyFooter'
export default {
name: 'App',
components: {
MyHeader,
MyList,
MyFooter,
},
data() {
return {
todos: [],
}
},
methods: {
// 添加
addTodo(todoObj) {
this.todos.unshift(todoObj)
},
// 选择
changeTodo(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
})
},
// 全选
checkAllTodo(done) {
this.todos.forEach((todo) => {
todo.done = done
})
},
//清除所有已完成的todo
clearAllTodo() {
this.todos = this.todos.filter((todo) => {
return !todo.done
})
},
},
}
</script>
<style>
</style>
MyHeader.vue
<template>
<div class="todo-header">
<input
type="text"
placeholder="请输入你的任务名称,按回车键确认"
v-model="title"
@keyup.enter="add"
/>
</div>
</template>
<script>
import { nanoid } from 'nanoid'
export default {
name: 'MyHeader',
data() {
return {
title: '',
}
},
props: ['receive'],
methods: {
add() {
if (!this.title.trim()) return alert('输入不能为空')
// 将用户的输入包装成一个todo对象
const todoObj = { id: nanoid(), title: this.title, done: false }
// 通知APP组件去添加一个todo对象
this.receive(todoObj)
// 清空输入框数据
this.title = ''
},
},
}
</script>
<style scoped>
</style>
MyList.vue
<template>
<ul class="todo-main">
<MyItem
v-for="todoObj in todos"
:key="todoObj.id"
:todo="todoObj"
:changeTodo="changeTodo"
:deleteTodo="deleteTodo"
/>
</ul>
</template>
<script>
import MyItem from './MyItem'
export default {
name: 'MyList',
components: { MyItem },
props: ['todos', 'changeTodo', 'deleteTodo'],
}
</script>
<style scoped>
</style>
MyFooter.vue
<template>
<div class="todo-footer" v-show="total">
<label>
<!-- <input type="checkbox" :checked="isAll" /> -->
<input type="checkbox" v-model="isAll"/>
</label>
<span>
<span>已完成{{ doneTotal }}</span>/全部{{total}}
</span>
<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
</div>
</template>
<script>
export default {
name: 'MyFooter',
props: ['todos','checkAllTodo','clearAllTodo'],
computed: {
total(){
return this.todos.length
},
doneTotal() {
// return this.todos.reduce((pre,current)=>{
// return pre+(current.done ? 1 :0)
// },0)
return this.todos.reduce(
(pre, current) => pre + (current.done ? 1 : 0),
0
)
},
isAll:{
get(){
return this.doneTotal === this.total && this.total > 0
},
set(value){
this.checkAllTodo(value)
}
}
},
methods:{
clearAll(){
this.clearAllTodo()
}
}
}
</script>
<style scoped>
</style>
MyItem.vue
<template>
<li>
<label>
<input
type="checkbox"
:checked="todo.done"
@change="handleCheck(todo.id)"
/>
<!-- 如下代码也能实现功能,但是不太推荐,因为有点违反原则,修改了props-->
<!-- <input
type="checkbox"
v-model="todo.done"
/> -->
<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', 'changeTodo', 'deleteTodo'],
methods: {
handleCheck(id) {
// 通知APP对象将对应的todo对象done取反
this.changeTodo(id)
},
handleDelete(id) {
if (confirm('确定删除吗?')) {
this.deleteTodo(id)
}
},
},
}
</script>
<style scoped>
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}
li button {
float: right;
display: none;
margin-top: 3px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
li:hover {
background-color: #ddd;
}
li:hover button {
display: block;
}
</style>
网友评论