vue组件通信

vue组件通信

组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用。一般来说,组件可以有以下几种关系:
在这里插入图片描述
如上图所示,A和B、B和C、B和D都是父子关系,C和D是兄弟关系,A和C是隔代关系

方法一、props/$emit

父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的

1、父组件向子组件传值

父组件通过 import 引入子组件,并注册,在子组件标签上添加要传递的属性,子组件通过 props 接收,接收有两种形式一是通过数组形式[‘要接收的属性’ ],二是通过对象形式{ }来接收,对象形式可以设置要传递的数据类型和默认值,而数组只是简单的接收
在这里插入图片描述

2、子组件向父组件传值

子组件通过$emit方法(用来触发事件,详情见官网)传递参数:
子组件:
在这里插入图片描述
父组件:
在这里插入图片描述

方法二、$emit / $on (中央事件总线)

这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
1、定义一个新的vue实例专门用于传递数据,并导出
在这里插入图片描述
2、定义传递的方法名和传输内容,点击事件或钩子函数触发eventBus.emit事件
在这里插入图片描述
3、接收传递过来的数据
注意:enentBus是一个另一个新的Vue实例,区分两个this所代表得vue实例,如果函数写成箭头函数,可以直接使用this,箭头函数内部不会产生新的this
在这里插入图片描述

方法三、Vuex

在这里插入图片描述
1、 简要介绍 Vuex 原理
Vuex 实现了一个单向数据流,在全局拥有一个 State 存放数据,当组件要更改 State 中的数据时,必须通过 Mutation 进行,Mutation 同时提供了订阅者模式供外部插件调用获取 State 数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走 Action,但 Action 也是无法直接修改 State 的,还是需要通过 Mutation 来修改 State 的数据。最后,根据 State 的变化,渲染到视图上。
主要流程:组件通过 dispatch 到 actions,actions 是异步操作,再 actions中通过 commit 到 mutations,mutations 再通过逻辑操作改变 state,从而同步到组件,更新其数据状态

方法四、provide / inject

provide / inject 是 2.2 新增的方法,可以以一个祖先组件向所有子孙后代注入依赖(一个内容)。
provider/inject:简单的来说就是在父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。
以上两者可以在父组件与子组件、孙子组件、曾孙子…组件数据交互,也就是说不仅限于prop的父子组件数据交互,只要在上一层级的声明的provide,那么下一层级无论多深都能够通过inject来访问到provide的数据
1.父级组件如下

<template>
	<div class="test">
		<son prop="data"></son>
	</div>
</template>

<script>
	export default {
		name: 'Test',
		provide: {
			name: 'Garrett'
		}
	}
</script>

2.孙子组件,注意这里是孙子组件,父级 -> 子组件 -> 孙子组件三个层级关系

<template>
	<div>
		{{name}}
	</div>
</template>

<script>
	export default {
		name: 'Grandson',
		inject: [name]
	}
</script>

这里可以通过inject直接访问其两个层级上的数据,其用法与props完全相同,同样可以参数校验等

方法五、$attrs / $listeners

多级组件嵌套需要传递数据时,通常使用的方法是通过 vuex。但如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用。为此 Vue2.4 版本提供了另一种方法----$attrs / $listeners

$ attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 interitAttrs 选项一起使用。
(简言之:接收除了props声明外的所有绑定属性(class、style除外))

//parent组件
<template>
	<div>
        <Son :name='name' :age='age'/>
    </div>
</template>
<script>
	export default {
        data() {
            return {
                name: 'Eric',
                age: '20'
            }
        }
    }
</script>

//Son组件
<template>
	<div>
        //此时Son组件把从父组件传来的数据,在传给孙组件
        <GrandSon v-bind='$attrs'/>
    </div>
</template>
<script>
	export default {
        props: ['name'],
        mounted() {
            //父组件共传来连个值,一个name, 一个age,由于name被props接收了,故$attrs 只有age属性
            console.log(this.$attrs) //{age: '20'}
        }
    }
</script>

//GrandSon组件
<template>
	<div>
        这是孙组件
    </div>
</template>
<script>
	export default {
        mounted() {
            //这样父祖组件就把数据传到了孙组件
            console.log(this.$attrs) // {age: '20'}
        }
    }
</script>

$ listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件
(简言之:接收除了带有.native事件修饰符的所有事件监听器)
接下来我们看个跨级通信的例子:

//parent组件
<template>
	<div>
        <Son @eventOne='eventHandler' @click.native='clickHandler'/>
    </div>
</template>
<script>
	export default {
        methods: {
            eventHandler() {
                console.log('触发了Parent中的eventHandler')
            },
            clickHandler() {
                console.log('触发了Parent中的clickHandler')
            }
        }
    }
</script>

//Son组件
<template>
	<div>
        //此时Son组件把从父组件传来的监听器,在传给孙组件
        <GrandSon v-on='$listerners'/>
    </div>
</template>
<script>
	export default {
        mounted() {
            //父组件监听了两个事件,一个eventOne, 一个click,由于click被native修饰了,故$listerners 只有eventOne事件
            console.log(this.$listerners) //{eventOne: fn}
            this.$emit('eventOne') //可以触发Parent组件中的eventHandler函数
        }
    }
</script>

//GrandSon组件
<template>
	<div>
        这是孙组件
    </div>
</template>
<script>
	export default {
        mounted() {
            //这样孙组件通过emit触发Parent组件中的监听函数
            console.log(this.$listerners) // {eventOne: fn}
            this.$emit('eventOne') //可以触发Parent组件中的eventHandler函数
        }
    }
</script>

方法六、$parent / $children与 ref
  • ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
  • $parent / $children:访问父 / 子实例
    需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。我们先来看个用 ref来访问组件的例子:
// component-a 子组件
export default {
  data () {
    return {
      title: 'Vue.js'
    }
  },
  methods: {
    sayHello () {
      window.alert('Hello');
    }
  }
}
// 父组件
<template>
  <component-a ref="comA"></component-a>
</template>
<script>
  export default {
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.title);  // Vue.js
      comA.sayHello();  // 弹窗
    }
  }
</script>

不过,这两种方法的弊端是,无法在跨级或兄弟间通信。

总结

常见使用场景可以分为三类:

  • 父子通信:
    父向子传递数据是通过 props,子向父是通过 events($ emit);通过父链 / 子链也可以通信($ parent / $ children);ref 也可以访问组件实例;provide / inject API;$ attrs/$listeners
  • 兄弟通信:
    Bus;Vuex
  • 跨级通信:
    Bus;Vuex;provide / inject API、$ attrs/$listeners
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值