关闭

vue组件之间的通信方式

IT985 1年前 ⋅ 341 阅读

组件可以说是一个具有独立功能的整体,但是当我们要将这些组件拼接在一起时,这些组件互相之间要建立联系,这个联系我们就称之为通信。

1. props和$emit/$on

介绍

最基本的父组件给子组件传递数据方式,将我们自定义的属性传给子组件,子组件通过$emit方法,触发父组件v-on的事件,从而实现子组件触发父组件方法

使用方法

父传子通过 props 传参

请参考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)

$emit/$on使用

下例详细的描述了 父组件通过传递一个事件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:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护

使用方法

请参考Vuex

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提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制

使用方法

slot

默认插槽

// 父组件
<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获取子组件的属性

使用方法

ref

// 父组件
<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使用方法

使用方法

$parent/$children

父组件
<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

  • 跨级通信: Bus;Vuex


全部评论: 0

    我有话说: