前言:
组件是 vue.js 最强大的功能之一,而组件实例的作用域之间是相互独立的,这就意味着不同组件之间的数据无法相互引用。一般来说,组件可以有以下几种关系:
1.父子
2.兄弟
3.跨级
本章只提供最基本的用法如下:
方法一、props/$emit
父组件 A 通过 props
的方式向子组件 B 传递,B to A 通过在 B 组件中 $emit
, A 组件中 v-on
的方式实现。
方法二、$emit/$on
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
注:当我们的项目比较大时,可以选择更好的状态管理解决方案 vuex。(这里不作多说)
不多说废话,直接上实现结果,如图:
父组件引用子组件MyInput、MyList、MyTotal,分为三块:input输入、ul列表显示、以及控制显示按钮。父组件代码如下:
<template>
<div class="layout">
<h1>{{ msg }}</h1>
<MyInput @add="add"/>
<MyList :list="list" @del="del" @ret="ret"/>
<MyTotal/>
</div>
</template>
<script>
import MyInput from './test/Input.vue'
import MyList from './test/List.vue'
import MyTotal from './test/Total.vue'
export default {
name: 'HelloWorld',
components:{
MyInput,MyList,MyTotal
},
data () {
return {
msg: 'Todolist',
list:[
{id:0,value:'打台球',status:0},
{id:1,value:'洗碗',status:1},
{id:2,value:'晒被子',status:0},
]
}
},
mounted(){
// console.log(Math.floor(Math.random() * 10000),1111)
},
methods:{
add(title){
this.list.push({
id:Math.floor(Math.random() * 1000),
value:title,
status:0
})
},
del(id){
console.log(id,222);
const newList = this.list.filter(item=>item.id!==id)
this.list = newList
},
ret(id){
console.log(id,222);
if(this.list[id].status === 0){
this.list[id].status = 1
}else{
this.list[id].status = 0
}
}
}
}
</script>
MyInput子组件代码如下:
<template>
<div class="myInput">
<input type="text" v-model="title"/>
<el-button type="primary" size="mini" @click="add">添加新事项</el-button>
</div>
</template>
<script>
import event from './event'
export default {
data(){
return {
title:''
}
},
methods:{
add(){
if(this.title === ''){
alert('请输入代办事件!')
return
}
this.$emit('add',this.title)
event.$emit('changeDom')
}
}
}
</script>
(事件中心)
如图中引用的event,来源何处呢?如果只是引用没有引入,那肯定是被丢弃的。这是我们需要引入一个event.js,如下:
由此看到,event.js只是引入了vue实例,所以以下子组件中使用的event都是vue的实例而已。
MyList子组件代码如下:
<template>
<div class="myList">
<template v-if="myStatus === 0">
<ul>
<li v-for="(item,index) in list" :key="item.id">
<div class="text">
<span >{{item.value}} </span>
<span v-if="item.status === 0"> [代办]</span>
<span v-if="item.status === 1"> [已办]</span>
</div>
<div class="bnt">
<el-button type="success" size="mini" @click="ret(item.id)">切换</el-button>
<el-button type="danger" size="mini" @click="del(item.id)">删除</el-button>
</div>
</li>
</ul>
</template>
<template v-if="myStatus === 1">
<ul>
<li v-for="(item,index) in list" :key="item.id">
<div class="text" v-if="item.status === 0"><span >{{item.value}}</span></div>
<div class="bnt">
</div>
</li>
</ul>
</template>
<template v-if="myStatus === 2">
<ul>
<li v-for="(item,index) in list" :key="item.id">
<div class="text" v-if="item.status === 1"><span >{{item.value}}</span></div>
<div class="bnt">
</div>
</li>
</ul>
</template>
</div>
</template>
<script>
import event from './event'
export default {
props:{
list:{
type: Array
}
},
data(){
return {
myStatus:0
}
},
mounted(){
event.$on('oAttle',this.myLog)
event.$on('changeDom',this.changeDom)
},
methods:{
del(id){
this.$emit('del', id)
event.$emit('onAttle', id)
},
myLog(status){
this.myStatus = status
event.$emit('changeColor',this.myStatus)
},
changeDom(){
this.myStatus =0
},
ret(id){
this.$emit('ret',id)
}
},
beforeDestroy(){
// 及时销毁,防止内存泄漏
event.$off('oAttle',this.myLog)
event.$off('changeDom',this.changeDom)
}
}
</script>
MyTotal子组件代码如下:
<template>
<div class="myList">
<el-button :type="butClor[0].type" size="mini" @click="myClick(statusArry[0])">全部</el-button>
<el-button :type="butClor[1].type" size="mini" @click="myClick(statusArry[1])">代办</el-button>
<el-button :type="butClor[2].type" size="mini" @click="myClick(statusArry[2])">已办</el-button>
</div>
</template>
<script>
import event from './event'
export default {
data(){
return {
statusArry:[0,1,2],
butClor:[
{id:0,type:"primary"},
{id:1,type:"primary"},
{id:2,type:"primary"}
]
}
},
mounted(){
event.$on('changeColor',this.changeColor)
},
methods:{
myClick(val){
if(val === 0){
event.$emit('oAttle',this.statusArry[0])
}else if(val === 1){
event.$emit('oAttle',this.statusArry[1])
}else{
event.$emit('oAttle',this.statusArry[2])
}
},
changeColor(status){
this.butClor = [
{id:0,type:"primary"},
{id:1,type:"primary"},
{id:2,type:"primary"}
]
// if(status === 0){
// this.butClor[0].type = 'danger'
// }else if(status === 1){
// this.butClor[1].type = 'danger'
// }else{
// this.butClor[2].type = 'danger'
// }
this.butClor[status].type='danger'
}
},
beforeDestroy(){
event.$off('changeColor',this.changeColor)
}
}
</script>
总结
常见使用场景可以分为三类:
-
父子通信:父向子传递数据是通过
也可以通过父链 / 子链也可以通信(props
,子向父是通过events($emit)
;$parent/$children)
;ref
也可以访问组件实例(本章不做多说)
-
兄弟通信:
$emit/$on、
Bus -
跨级通信:Vuex、Bus