vue组件通信

前言

大家对vue组件通信的方式应该都有了解,下面我来说下自己知道的通信方式

  • props
  • $emit 触发自定义事件
  • v-model 双向绑定
  • $refs
  • c h i l d r e n / children/ children/parent
  • $root
  • a t t r s / attrs/ attrs/listeners
  • slot插槽
  • provide/inject
  • EventBus
  • Vuex

props

最常见的组件通信方式了,常用于父子间通信.

注意: 因为vue中数据是单向向下流动的,所以不要在子组件中直接修改props传递下去的数据

父组件

  <template>
    <div class="father">
      <button @click="changeMsg">修改信息</button>
      <SonComponent :msg="msg"/>
    </div>
  </template>

  // script
  data(){
    return{
      msg:''
    }
  },
  methods:{
    changeMsg(){
      this.msg='我是父组件props传过来的数据';
    }
  }

子组件

子组件接收的话有两种方式, 可以写数组或者对象

  <template>
    <div>
      我是props数据: {{ msg }}
    </div>
  </template>

  // script
  props:['msg'],
  // props:{
  //   msg:{
  //     type: String,         // props传递的数据类型
  //     default: '默认信息',   // 默认值
  //     require: true,        // 必传
  //     validate: /\*/        // 校验规则
  //   }
  // },

效果

在这里插入图片描述

$emit

一般用于父组件传递事件给子组件,子组件通过$emit进行触发

父组件

<template>
  <div class="father">
    <SonComponent :msg="msg" @changeMsg="changeMsg"/>
  </div>
</template>

// script
methods:{
  changeMsg(msg){
    msg=msg??'我是父组件props传过来的数据';
    this.msg=msg;
  }
}

子组件

  <div>
    <button @click="$emit('changeMsg','emit修改的数据')">emit修改</button>
    我是props数据: {{ msg }}
  </div>

效果

在这里插入图片描述

v-model

首先我们需要知道,v-model的话是v-on以及v-bind的语法糖,一般我们用于双向绑定在input上,但是我们也可以用其对父子组件进行通信。

vue2 vue3有点区别,可以去看看官方文档 V2官方文档
V3官方文档

我用的是V2的,需要在写model配置项

父组件

  <div class="father">
    <SonComponent v-model="msg"/>
  </div>

子组件

  <div>
    <button @click="$emit('modelChange','model修改的数据')">model修改</button>
    我是props数据: {{ newMsg }}
  </div>

  // script
  model:{
    prop:'newMsg',  //父组件传来的值选择用 名为newMsg 的prop来接收,所以必须下面的props必须要写,且对应
    event:'modelChange' //自定义父组件传递过来的事件名,通过emit触发时,第二个参数为父组件model绑定数据的新值
  },
  props:['newMsg'],

效果

在这里插入图片描述

$refs

我们通常会将 $refs 绑定在DOM元素上,来获取DOM元素的 attributes。在实现组件通信上,我们也可以将 $refs 绑定在子组件上,从而获取子组件实例。

ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素; 如果用在子组件上,引用就指向组件实例。

父组件

  <div class="father">
    <button @click="changeMsg">修改信息</button>
    <SonComponent ref="son"/>
    {{ msg }} 
  </div>

  // script
  methods:{
    changeMsg(){
      console.log(this.$refs.son)
      this.msg=this.$refs.son.sonMsg;
    }
  }

子组件

  data() {
    return {
      sonMsg:'我是son中的数据'
    };
  },

效果

通过$refs访问组件得到的是组件实例
在这里插入图片描述
在这里插入图片描述

c h i l d r e n / children/ children/parent

我们可以在 Vue 中直接通过this.$parent来获取当前组件的父组件实例(如果有的话),通过this.$children[index]获取对应的子组件实例

父组件

  <div class="father">
    <button @click="changeMsg">修改信息</button>
    <SonComponent/>
    {{ msg }} 
  </div>

  // script
  
  methods:{
    changeMsg(){
      console.log(this.$children) // 获取的是子组件数组,需要通过索引值访问具体的子组件
      this.$children[0].changeSonMsg('Father给你的数据') 
    }
  }

子组件

  <div>
    son的sonMsg:{{sonMsg}}
    <br/>
    parent的msg:{{parMsg}}
  </div>

  // script
  data() {
    return {
      sonMsg:'我是son中的数据',
      parMsg:this.$parent.msg
    };
  },
  methods: {
    changeSonMsg(msg){
      this.sonMsg=msg;
    }
  },

效果

$children获取的子组件是数组,需要用索引获取具体的实例

$parent获取父组件只有一个

在这里插入图片描述

$root

获取当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。通过 $root ,我们可以实现组件之间的跨级通信。

通过this.$root获取根实例,注意不是App.vue

a t t r s / attrs/ attrs/listeners

a t t r s :包含了父作用域中不被认为 ( 且不预期为 ) p r o p s 的特性绑定 ( ‘ c l a s s ‘ 和 ‘ s t y l e ‘ 除外 ) 。当一个组件没有声明任何 p r o p s 时,这里会包含所有父作用域的绑定 ( ‘ c l a s s ‘ 和 ‘ s t y l e ‘ 除外 ) ,并且可以通过 ‘ v − b i n d = " attrs:包含了父作用域中不被认为 (且不预期为) props 的特性绑定 (`class` 和 `style` 除外)。当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定 (`class` 和 `style` 除外),并且可以通过 `v-bind=" attrs:包含了父作用域中不被认为(且不预期为)props的特性绑定(classstyle除外)。当一个组件没有声明任何props时,这里会包含所有父作用域的绑定(classstyle除外),并且可以通过vbind="attrs"` 传入内部组件

l i s t e n e r s :包括父作用域中的 ‘ v − o n ‘ 事件监听器(但不包括添加了 ‘ . n a t i v e ‘ 修饰器的那些事件监听器)。可以通过 ‘ v − o n = " listeners:包括父作用域中的 `v-on` 事件监听器(但不包括添加了 `.native` 修饰器的那些事件监听器)。可以通过 `v-on=" listeners:包括父作用域中的von事件监听器(但不包括添加了‘.native修饰器的那些事件监听器)。可以通过von="listeners"`,将这些事件监听器向下传入到组件内部

父组件

  <SonComponent @changeInfo="changeInfo" :info="info" :msg="msg"/>

  // script
  data(){
    return{
      msg:'默认值',
      info:'哈哈哈哈'
    }
  },
  methods:{
    changeInfo(info){
      this.info=info
    },
  }

子组件

  <p>子组件的$attrs:  {{ $attrs.info }}</p> //子组件可以通过$attr直接获取到父组件传递下来的数据
  <GrandSon v-bind="$attrs" v-on="$listeners"/> //给孙子组件传递$attrs,不能用props接收需要传递下去的数据,不需要传递的可以接收

  // script
  props:['msg'] //接收msg, 那么传递给下级组件的$attrs中就没有msg了

孙子组件

触发$listeners传递下来的事件就和触发自定义事件一样 用$emit

孙子的$attrs没有值是因为info被自己接收了、msg被上一级组件接收了

  <div>
    <button @click="$emit('changeInfo','孙子组件的传值')">修改爷爷的info</button>
    <p>孙子的props:{{info}}</p>
    <p>孙子的$attrs:{{$attrs}}</p>
  </div>

  // script
  props:{
    info:{
      type:String,
      default:'孙子的默认值'
    }
  },

效果

在这里插入图片描述

slot插槽

  • 匿名插槽(父->子)

子组件定义了solt,但未提供名字,这就是匿名插槽,也叫做默认插槽,只要出现的父组件中,未指定插槽名字的内容,都会默认放到匿名插槽里。

  • 具名插槽(父->子)

所谓具名插槽,就是给插槽命了名字,父组件放进来的内容,需要指定插槽的名称,这个时候才会被分发到这个具名插槽中。

  • 作用域插槽(子->父)

有时让插槽内容能够访问子组件中才有的数据是很有用的。所以提供了作用域插槽

父组件

  <SonComponent>
    {/* defaultObj 上获得的值是匿名插槽中 v-bind 绑定的所有值的对象 */}
    <template v-slot:default="defaultObj">  
      <div>
        {{ defaultObj }}
        <p>{{defaultObj.defaultMsg}}</p>
      </div>
    </template>
    {/* 直接将nameMsg解构出来 */}
    <template v-slot:name="{nameMsg}"> 
      <div>
        {{ nameMsg }}
        <p>{{`父组件传递的信息${info}`}}</p>
      </div>
    </template>
  </SonComponent>

  // script
  data(){
    return{
      info:'哈哈哈哈'
    }
  },

子组件

  <slot :defaultMsg="defaultMsg"></slot>
  <slot name="name" :nameMsg="nameMsg"></slot>

  // script
  
  data() {
    return {
      defaultMsg:'匿名插槽中使用作用域插槽',
      nameMsg:'具名插槽中使用作用域插槽'
    };
  },

效果

在这里插入图片描述

provide/inject

**provide:**是一个对象,或者是一个返回对象的函数。该对象包含可注入其子孙的 property ,即要传递给子孙的属性和属性值。
**injcet:**一个字符串数组,或者是一个对象。当其为字符串数组时,使用方式和props十分相似,只不过接收的属性由data变成了provide中的属性。当其为对象时,也和props类似,可以通过配置default和from等属性来设置默认值,在子组件中使用新的命名属性等。

:::tip
注意:provideinject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象(引用类型),那么其对象的属性还是可响应的
:::

    // 爷爷组件
    <button @click="changeMsg('修改后的msg')">修改msg</button>
    <p>爷爷的info:{{info}}</p>
    <p>爷爷的msg:{{msg}}</p>
    <SonComponent/>
    <button @click="changeInfo('修改后的info')">修改info</button> 

    provide(){
      return{
        msg:this.msg,
        info:this.info
      }
    },  
    data(){
      return{
        msg:'默认值',
        info:{msg:'哈哈哈哈'}
      }
    },
    methods:{
      changeInfo(info){
        this.info.msg=info
      },
      changeMsg(msg){
        this.msg=msg;
      }
    }


  // 孙子组件
  <p>孙子收到的msg:{{ msg }}</p>
  <p>孙子收到的info:{{ info.msg }}</p>

    
  inject:['info','msg'],

效果

在这里插入图片描述

EventBus 事件总线

eventBus又称事件总线,通过注册一个新的Vue实例,通过调用这个实例的 e m i t 和 emit和 emiton等来监听和触发这个实例的事件,通过传入参数从而实现组件的全局通信。它是一个不具备 DOM 的组件,有的仅仅只是它实例方法而已,因此非常的轻便。
我们可以通过在全局Vue实例上注册:

// main.js 文件中
Vue.prototype.$Bus = new Vue()
  // 爷爷组件
  <p>爷爷的msg:{{msg}}</p>
  <SonComponent/>

  
  data(){
    return{
      msg:'默认值'
    }
  },
  created(){
    this.$Bus.$on('changeMsg',this.changeMsg)
  },
  beforeDestroy(){
    this.$Bus.$off('changeMsg')  //组件销毁前 解绑事件
  },
  methods:{
    changeMsg(msg){
      this.msg=msg;
    }
  }
  
  
  // 孙子组件
  <button @click="$Bus.$emit('changeMsg','孙子组件触发了changeMsg事件')">触发爷爷组件上的事件</button>

vuex 大家可以直接去看看,挺多的

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值