向子组件传递对象
使用v-bind
形式向子组件传递对象:
<template>
<ul class="todo-main">
<!-- 使用:todo,利用v-bind内容是js表达式的方式,将todoObj传递给子组件MyItem -->
<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj"/>
</ul>
</template>
<script>
import MyItem from './MyItem'
export default {
name:'MyList',
components: {MyItem},
data() {
return {
todos: [
{id:'0001', title:'吃饭', done:true},
{id:'0002', title:'睡觉', done:false},
{id:'0003', title:'看电视', done:true},
]
}
},
}
</script>
子组件接收对象,并进行显示:
<template>
<li>
<label>
<input type="checkbox" :checked="todo.done"/>
<span>{{todo.title}}</span>
</label>
<button class="btn btn-danger" style="display:none">删除</button>
</li>
</template>
<script>
export default {
name: 'MyItem',
props:['todo'] // 接收父组件传入的对象
}
</script>
生成唯一流水号
可以使用UUID生成唯一流水号,但是UUID组件比较重,可以使用轻量版的nanoid代替:
npm i nanoid
用法:
import {nanoid} from 'nanoid'
let id = nanoid();
调用父组件的方法,给父组件传值
父组件定义方法,并传递给子组件:
<template>
<div id="app">
<div class="todo-container">
<div class="todo-wrap">
<!-- 将addTodo方法传递给子组件MyHeader -->
<MyHeader :addTodo="addTodo"/>
</div>
</div>
</div>
</template>
<script>
import MyHeader from './components/MyHeader'
export default {
name: 'App',
components: {MyHeader},
data() {
return {
todos: [
{id:'0001', title:'吃饭', done:true},
{id:'0002', title:'睡觉', done:false},
{id:'0003', title:'看电视', done:true},
]
}
},
methods: {
// 定义addTodo方法
addTodo(todo) {
this.todos.unshift(todo)
}
}
}
</script>
子组件中接收函数,并在需要时调用:
<template>
<div class="todo-header">
<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add"/>
</div>
</template>
<script>
import {nanoid} from 'nanoid'
export default {
name:'MyHeader',
props: ['addTodo'], // 接收父组件的addTodo方法
methods: {
add(e) {
const todoObj = {id:nanoid(), title:e.target.value, done:false};
// 调用父组件的addTodo方法,参数也可以通过父组件方法正常传递给父组件
this.addTodo(todoObj);
}
}
}
</script>
复选框的操作
方式1:
使用:checked
显示复选框是否被选中。使用@change
绑定事件当选择状态变化时触发方法
<template>
<div class="todo-footer" v-show="total">
<!-- 使用:checked显示当前复选框是否被选中。 当选中的状态改变时触发checkAll事件 -->
<input type="checkbox" :checked='isAll' @change="checkAll"/>
</div>
</template>
<script>
export default {
name:'MyFooter',
computed: {
// 定义计算属性isAll, 用来展示复选框是否被选中
isAll() {
return (this.total === this.checkedCount) && (this.total > 0);
},
},
methods: {
// 复选框选中或取消选择时触发该事件
checkAll(e) {
this.checkAllTodo(e.target.checked);
}
}
}
</script>
方式2:
使用v-model
双向绑定:
<template>
<div class="todo-footer" v-show="total">
<!-- 使用v-model进行双向绑定 -->
<input type="checkbox" v-model='isAll'/>
</div>
</template>
<script>
export default {
name:'MyFooter',
computed: {
// 使用计算属性的完整写法,给出getter/setter
isAll: {
get(){
return (this.total === this.checkedCount) && (this.total > 0);
},
set(value) { // 获取复选框是否被选中
this.checkAllTodo(value);
}
},
}
}
</script>
总结
组件化编码流程:
- 拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突
实现动态组件:考虑好数据的存放位置,数据是一个组件在用还是一些组件在用:
- 一个组件在用:放在组件自身即可
- 一些组件在用:放在他们共同的父组件上(即状态提升)
- 实现交互:从绑定事件开始
props适用于:
- 父组件到子组件的通信
- 子组件到父组件的通信(要求父组件先给子组件传递一个函数)
使用v-model
是要注意:v-model
绑定的值不能是props传过来的值,因为props是不可以修改的
props传过来的值如果是对象类型的值,修改对象中的属性时vue不会报错,但是不推荐这么做。