组件可以说是一个具有独立功能的整体,但是当我们要将这些组件拼接在一起时,这些组件互相之间要建立联系,这个联系我们就称之为通信。
1. props和$emit/$on
介绍
最基本的父组件给子组件传递数据方式,将我们自定义的属性传给子组件,子组件通过$emit方法,触发父组件v-on的事件,从而实现子组件触发父组件方法
使用方法
父传子通过 props 传参
请参考
先定义了两个组件,父组件parent 和子组件son,子组件接收父组件传过来的参数,子组件通过props属性来接收父组件传 过来的参数,props有几种写法,第一种是以数组的形式接收参数,第二种是以对象的形式接收参数,而且还可以设默认值
// 父组件 parent
<template>
<div class="hello">
<son :msg="msg"></son>
</div>
</template>
<script>
import son from './son.vue'
export default {
components:{
son
},
data(){
return{
msg:"我是父亲"
}
}
}
</script>
---------------------------------------------------------------------------------
// 子组件 son
<template>
<div>{{msg}}</div>
</template>
<script>
export default {
props: {
// msg: String,
msg:{
type:String,
default:"我是儿子" // 设置默认值
}
},
}
</script>
子传父 通过事件形式($emit)
下例详细的描述了 父组件通过传递一个事件changeEmit给子组件 子组件通过$emit触发父组件传过来的事件, 并且可以进行传参 $emit第一个参数 是事件名 第二个参数是进行传递给父组件的参数
// 父组件
<template>
<div class="hello">
{{msg}}
<son @changeEmit="changeEmit"></son>
</div>
</template>
<script>
import son from './son.vue'
export default {
components:{
son
},
data(){
return{
msg:"我是父亲"
}
},
methods:{
changeEmit(value){
this.msg = value
console.log('',value)
}
}
}
</script>
子组件
<template>
<div>{{msg}}</div>
</template>
<script>
export default {
data(){
return{
msg:"我是儿子emit"
}
},
mounted() {
// 触发事件 改变父组件的值 d
this.$emit('changeEmit',this.msg)
}
}
</script>
2.EventBus
介绍
EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念, 就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件, 所以组件都可以上下平行地通知其他组件
平常我们采用更多的是父传子,子传父,当遇到兄弟之间的组件通信的时候 就可以使用EventBus
使用方法
下面是简单的使用方法
// EventBus.js
import Vue from 'vue'
export default new Vue({})
// component-a.js
import EventBus from './EventBus.js'
export default {
created () {
EventBus.$on('event-name', (preload) => {
// ...
})
}
}
// component-b.js
import EventBus from './EventBus.js'
export default {
created () {
EventBus.$emit('event-name', preload)
}
}
3. VUEX
介绍
Vuex 是什么? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化 Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。 组成部分
-
state:用于数据的存储,是store中的唯一数据源
-
getters:如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
-
mutations:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,并且不能用于处理异步事件
-
actions:类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
-
modules:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护
使用方法
请参考
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
son:"",
son1:""
},
mutations: {
changeSon(state,val){
state.son1 = val
}
},
actions: {
}
})
// 父组件
<template>
<div class="hello">
{{msg}}
<son></son>
<son1></son1>
</div>
</template>
<script>
import son from './son.vue'
import son1 from './son1.vue'
export default {
components:{
son,
son1
},
data(){
return{
msg:"我是父亲"
}
},
}
</script>
// 子组件son
<template>
<div>
<span>{{sonValue}}</span>
<p>接收来自son1的值{{son1}}</p>
</div>
</template>
<script>
export default {
data() {
return {
sonValue: "我是son1"
}
},
computed: {
son1() {
return this.$store.state.son1
}
}
}
</script>
// 子组件son1
<template>
<div>
<span>{{sonValue}}</span>
<button @click="btn">在son1里面改变son的值</button>
</div>
</template>
<script>
export default {
data(){
return{
sonValue:"我是son2"
}
},
methods:{
btn(){
this.$store.commit('changeSon','哈哈哈哈,收到了吗')
}
}
}
</script>
4.slot插槽
介绍
插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制
使用方法
默认插槽
// 父组件
<template>
<div>
我是父组件
<slotOne1>
<p style="color:red">我是父组件插槽内容</p>
</slotOne1>
</div>
</template>
// 子组件
<template>
<div class="slotOne1">
<div>我是slotOne1组件</div>
<slot></slot>
</div>
</template>
具名插槽
在一个组件里可能会多处使用插槽,我们希望在不同的插槽处插入不同的内容,此时便需要进行区分,<slot> 元素有一个特殊的特性:name。这个特性可以用来定义插槽的名字,在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用
// 父组件
// 在父组件中使用template并写入对应的slot值来指定该内容在子组件中现实的位置(当然也不用必须写到template),没有对应值的其他内容会被放到子组件中没有添加name属性的slot中
<template>
<div>
我是父组件
<slot-two>
<p>啦啦啦,啦啦啦,我是卖报的小行家</p>
<template slot="header">
<p>我是name为header的slot</p>
</template>
<p slot="footer">我是name为footer的slot</p>
</slot-two>
</div>
</template>
// 子组件
// 在子组件中定义了三个slot标签,其中有两个分别添加了name属性header和footer
<template>
<div class="slottwo">
<div>slottwo</div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
</template>
作用域插槽
为了使父组件的插槽内容可以使用子组件的数据,可以在 <slot> 元素上绑定想要传递的数据,此特性被称为插槽 prop。同时在父级作用域中,给 v-slot 带一个值来定义我们提供的插槽 prop 的名字,便可获取到。但此内容只在 <template>作用域内可用
//父组件
//在父组件上使用slot-scope属性,user.data就是子组件传过来的值
<template>
<div>
我是作用域插槽
<slot-three>
<template slot-scope="user">
<div v-for="(item, index) in user.data" :key="index">
{{item}}
</div>
</template>
</slot-three>
</div>
</template>
//子组件
//在子组件的slot标签上绑定需要的值
<template>
<div>
我是作用域插槽的子组件
<slot :data="user"></slot>
</div>
</template>
<script>
export default {
name: 'slotthree',
data () {
return {
user: [
{name: 'Jack', sex: 'boy'},
{name: 'Jone', sex: 'girl'},
{name: 'Tom', sex: 'boy'}
]
}
}
}
</script>
5. ref 和refs
介绍
refs是获取子组件的实例,ref如果是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素; 如果用在子组件上,引用就指向组件实例,可以通过实例直接调用组件的方法或访问数据, 父组件在子组件上首先绑定ref属性然后通过$refs获取子组件的属性
使用方法
// 父组件
<template>
<div class="hello">
{{msg}}
<button @click="changeSon">改变子组件值</button>
// 绑定 son属性
<son ref="son"></son>
</div>
</template>
<script>
import son from './son.vue'
export default {
components:{
son
},
data(){
return{
msg:"我是父亲"
}
},
methods:{
changeSon(){
// 改变子组件的值
this.$refs.son.sonValue ='父组件传值了'
}
}
}
</script>
// 子组件
<template>
<div>
<span>{{sonValue}}</span>
</div>
</template>
<script>
export default {
data(){
return{
sonValue:"我是子组件"
}
},
}
</script>
6.$parent/$children
介绍
子实例可以用 this.$parent 访问父实例,子实例被推入父实例的 $children 数组中。 注意的是因为一个父组件里面可以包含很多子组件 因此 $children是一个数组,而$parent是一个对象,他们 两个的值不一样 通过$parent和$children就可以访问组件的实例,拿到实例代表什么?代表可以访问此组件的所有方法和data使用方法
使用方法
父组件
<template>
<div class="hello">
{{msg}}
<button @click="changeSon">改变子组件值</button>
<son :msg="msg"></son>
</div>
</template>
<script>
import son from './son.vue'
export default {
components:{
son
},
data(){
return{
msg:"我是父亲"
}
},
methods:{
changeSon(){
// 父组件进行传值给子组件
this.$children[0].sonValue ='父组件传值了'
}
}
}
</script>
子组件
<template>
<div>
<span>{{sonValue}}</span>
<button @click="changeParent">改变父组件值</button>
</div>
</template>
<script>
export default {
data(){
return{
sonValue:"我是子组件"
}
},
methods:{
changeParent(){
// 子组件进行传值给父组件
this.$parent.msg="子组件传值了"
}
}
}
</script>
总结
常见使用场景可以分为三类:
-
父子通信: 父向子传递数据是通过 props,子向父是通过 events($emit);通过父链 / 子链也可以通信($parent / $children);ref 也可以访问组件实例以及slot插槽;
-
兄弟通信: Bus;Vuex
-
跨级通信:
注意:本文归作者所有,未经作者允许,不得转载