Vue组件间的通信方式

一、通过 props 传递

子组件设置props属性,定义接收父组件传递过来的参数

父组件在使用子组件标签中通过字面量来传递值

# 父组件

<Children name="Mike" age=18 />
# 子组件

props: {

    // 字符串形式
    name: String // 接收的类型参数

    // 对象形式
    age:{  
       type: Number, // 接收的类型
       defaule: 18,  // 默认值为
       require: true // 属性必须传递
    }

}

二、通过 $emit 触发自定义事件

子组件通过$emit触发自定义事件,$emit第二个参数为传递的数值

父组件绑定监听器获取到子组件传递过来的参数

# 父组件

<Children @add="cartAdd($event)" />
# 子组件

this.$emit('add', 'xxx')

三、使用 ref 或 $children

1、ref

ref属性可以给任何组件或元素赋一个唯一的标识符,通过这个标识符可以直接访问对应的组件或元素。

注意:$refs属性是一个对象,它的属性就是各个ref属性的标识符,属性值则对应着实际的组件或元素。

相对于$children属性,$refs属性更加灵活和便于使用,因为可以给任何组件或元素添加ref属性,并且不需要知道索引值。但是,需要注意避免命名冲突。

# 父组件

<Children ref="childeren" />

this.$refs.children  // 获取子组件实例,通过子组件实例就能调用子组件自身的属性和方法

2、$children

$children属性是一个数组,包含了当前组件中所有的直接子组件。

注意:$children属性只包括直接子组件,而不包括孙子组件或更深层次的组件。如果想要访问所有的子孙组件,可以使用递归的方式来遍历整个组件树。

<template>

  <div>

    <child-component ref="child"></child-component>

  </div>

</template>

 

<script>

import ChildComponent from '@/path/ChildComponent.vue'

 

export default {

  name: 'ParentComponent',

  components: {

    ChildComponent

  },

  mounted() {

    console.log(this.$children[0]) // 访问第一个子组件实例

    console.log(this.$refs.child) // 通过ref属性访问子组件实例

  }

}

</script>

四、EventBus

创建一个中央时间总线EventBus

兄弟组件通过$emit触发自定义事件,$emit第二个参数为传递的数值

另一个兄弟组件通过$on监听自定义事件

// 创建一个中央时间总线类

class Bus {

  constructor() {

    this.callbacks = {};   // 存放事件的名字

  }

  $on(name, fn) {

    this.callbacks[name] = this.callbacks[name] || [];

    this.callbacks[name].push(fn);

  }

  $emit(name, args) {

    if (this.callbacks[name]) {

      this.callbacks[name].forEach((cb) => cb(args));

    }

  }

}
# main.js

Vue.prototype.$bus = new Bus() // 将$bus挂载到vue实例的原型上

// 另一种方式

Vue.prototype.$bus = new Vue() // Vue已经实现了Bus的功能
# 子组件1

this.$bus.$emit('foo')


# 子组件2

this.$bus.$on('foo', this.handle)

 

五、$parent 或 $root

通过共同祖辈$parent 或者 $root搭建通信

# 父组件

<div>

    <!-- 子组件1 -->
    <Children1 />

    <!-- 子组件2 -->
    <Children2 />

</div>
# 子组件1

this.$parent.on('add', this.add);

或者

this.$root.on('add', this.add)
# 子组件2

this.$parent.emit('add', '传输数据');

或者

this.$root.emit('add', '传输数据');

 

六、$attrs 与 $listeners

$attrs:继承所有的父组件属性(除了 prop 传递的属性、class 和 style ),一般用在子组件的子元素上,可以通过 v-bind="$attrs" 传⼊。

$listeners:是一个对象,里面包含了作用在这个组件上的所有监听器,可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。(相当于子组件继承父组件的事件)。

1、给子组件传值

# 父组件

<Children foo="foo" />
# 子组件

# 子组件并未在props中声明foo

<p>{{ $attrs.foo }}</p>

2、给孙组件传值

# 父组件

<Children msg="xxx" @some-event="onSomeEvent" @some-event2="onEvent2" />
# 子组件

<Grandson v-bind="$attrs" v-on="$listeners" />

this.$emit('some-event2', '传输的数据')
# 孙组件

<div @click="$emit('some-event', '传输的数据')">

    {{ msg }}

</div>

 

七、Provide 与 Inject

在祖先组件定义provide属性,返回传递的值或方法

在后代组件通过inject接收组件传递过来的值或方法

1、vue2 中的用法

默认情况下,provide/inject 绑定并不是响应式的。如果我们想对祖先组件中的更改做出响应,我们需要将 provide 传值进行改变,传入一个响应式对象。

# 祖先组件

provide(){
    return {   
      obj: this.obj, // 传入一个响应式对象
      changeVal: this.changeName // 传入一个方法
    }
},

data(){
    return {
      obj: {
        name: "leo"
      }
    }
},

methods:{
    changeName(val) { // 触发该方法执行
      this.obj.name = val
    }
}
# 后代组件

<template>

  <div>
    <span>{{ obj.name }}</span>
  </div>

</template>


<script>

export default {
 
  inject:[
    "obj", // 接收一个响应式对象
    "changeVal" // 接收一个方法
  ],    
  
  methods:{

    changeName(){
      this.changeVal("lion")   
    }

  }
};

</script>

2、vue3 中的用法

如果是在vue3中,则我们可以通过传递一个 ref property 或 reactive 对象给 provide 来改变这种行为。

1. provide

在 setup() 中使用 provide 时,我们首先从 vue 显式导入 provide 方法。这使我们能够调用 provide 来定义每个 property。

provide 函数允许你通过两个参数定义 property:

  1. name (<String> 类型)
  2. value

2. inject

在 setup() 中使用 inject 时,也需要从 vue 显式导入。导入以后,我们就可以调用它来定义暴露给我们的组件方式。

inject 函数有两个参数:

  1. 要 inject 的 property 的 name
  2. 默认值 (可选)

为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 或 reactive。 

# 父组件

<template>
  <Children />
</template>
 
<script>

import { provide, reactive, ref } from 'vue'

import Children from './Children.vue'
 
export default {

  components: {
    Children
  },

  setup() {
    const location = ref('North Pole');

    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })
 
    // 修改方法
    const updateLocation = () => {
      location.value = 'South Pole'
    }
 
    provide('location', location)
    provide('geolocation', geolocation)
    provide('updateLocation', updateLocation)     // 传入一个方法
  }
}
</script>
# 子组件

<script>

import { inject } from 'vue'
 
export default {
  setup() {
    const userLocation = inject('location', 'The Universe')
    const userGeolocation = inject('geolocation')
    const updateUserLocation = inject('updateLocation')
 
    return {
      userLocation,
      userGeolocation,
      updateUserLocation      // 执行该方法,触发祖先组件方法执行,从而改变数据
    }
  }
}

</script>

如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly

<template>
  <Children />
</template>
 
<script>

import { provide, reactive, readonly, ref } from 'vue';

import Children from './Children.vue';
 
export default {

  components: {
    Children
  },

  setup() {
    const location = ref('North Pole');

    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })
 
    const updateLocation = () => {
      location.value = 'South Pole'
    }

    // 使用readonly,数据只读
    provide('location', readonly(location))
    provide('geolocation', readonly(geolocation))
    provide('updateLocation', updateLocation)
  }
}
</script>

 

八、Vuex

复杂关系的组件数据传递可以通过vuex存放共享的变量。

Vuex作用相当于一个用来存储共享变量的容器

  • state用来存放共享变量的地方
  • getter,可以增加一个getter派生状态,(相当于store中的计算属性),用来获得共享变量的值
  • mutations用来存放修改state的方法。
  • actions也是用来存放修改state的方法,不过action是在mutations的基础上进行。常用来做一些异步操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值