vue组件间通信方式

本文详细介绍了Vue组件通信的多种方式,包括父子组件通信(props + $emit、$parent/$children、ref + refs、provide/inject、attrs/attrs绑定)和兄弟组件间通信(父组件中转、eventBus、localStroage/sessionStroage、Vuex)。内容涵盖了各种通信方式的使用场景、优缺点和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

本文主要讲述了vue组件通信的几种方式,分为父子间通信和兄弟组件间通信两大类分别介绍,如有补充或有误的地方,可随时滴滴我哦~

一、父子组件通信

1、props + $emit(常用)

(1)父向子传参

父组件parent.vue:

引入子组件,通过v-bind传参

<template>
    <div class="myVue">
        <children :data="msg"></children>
    </div>
</template>
<script>
import children from './children'
export default {
  name: 'parent',
  data () {
    return {
      msg: '父传子'
    }
  },
  components: {
    children
  }
}
</script>

子组件children.vue

通过props引入所传参数

<template>
 <div>{{data}}</div>
</template>

<script>
export default {
  data () {
    return {
    }
  },
  props: ['data']
}
</script>
<style lang="less" scoped>
  div {
    font-size: 40px;
  }
</style>

props还可以对参数进行验证:

 props: {
      data: {
          type: String,   // 传入类型
          required: true, // 是否必须
          default: ''     // 默认值
      } 
  }

(2)子向父传参

子组件:children.vue

通过v-on绑定的函数,在函数里用 this.$emit 传参

<template>
 <div @click="func">点击向父组件传参</div>
</template>

<script>
export default {
  data () {
    return {
      msg: '子向父'
    }
  },
  methods: {
    func () {
      this.$emit('funcParent', this.msg)
    }
  }
}
</script>
<style lang="less" scoped>
  div {
    font-size: 40px;
  }
  div:hover {
    cursor: pointer;
  }
</style>

父组件:parent.vue

通过v-on接受传进来的函数,并在自定义函数中接受参数

<template>
    <div class="myVue">
        <children @funcParent="func"></children>
    </div>
</template>
<script>
import children from './children'
export default {
  name: 'parent',
  data () {
    return {
    }
  },
  components: {
    children
  },
  methods: {
    func (data) {
      console.log(data)
    }
  }
}
</script>

补充知识:

$emit是挂载在vue实例上的事件方法,使用方式:

vm.$emit( eventName, […args] )

参数:eventName是触发的事件名称 (string) , […args]是带的多个参数

作用: 触发当前实例上的eventName事件,将所带参数传给监听器回调

 2、$children + $parent(vue3已移除)

(1)父向子传参

使用 this.$parent 可以直接访问该组件的父实例或组件

组件可以通过this.$parent 访问它所有的父组件实例,不是响应式的

(2)子向父传参

组件可以通过this.$children 访问它所有的子组件实例,不是响应式的

3、ref + refs

在普通dom上加ref属性,通过this.$refs.name获取到的就是dom元素;在组件上加ref属性,通过this.$refs.name获取到的就是组件实例,所以可以访问组件实例的方法和数据,如下:

父组件parent.vue:

<template>
    <div class="myVue">
        <children ref="child"></children>
        <p>{{childVal}}</p>
    </div>
</template>
<script>
import children from './children'
export default {
  name: 'parent',
  data () {
    return {
      msg: '父传子',
      childVal: ''
    }
  },
  components: {
    children
  },
  mounted(){
      this.childVal = this.$refs.child.name;
  }
}
</script>

子组件:children.vue :

<template>
    <button @click="handleClick">点我</button>
</template>

<script>
export default {
    data() {
        return {
            name: '小明'
        }
    }
}
</script>

注:

  • 在初始渲染的时候,他们还不存在,所以不能访问,即在mounted才开始可以访问
  • 不是响应式的,即子元素数据修改了,但是父元素不会实时更新

4、provide + inject

允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效 。

  • provide :一个对象或返回一个对象的函数。该对象包含可注入其子孙的 property。
  • inject:一个字符串数组,或一个对象。通过 inject 向子组件中注入变量。

父组件parent.vue:

<template>
    <div class="myVue">
        <children></children>
    </div>
</template>
<script>
import children from './children'
export default {
  name: 'parent',
  components: {
    children
  },
  provide: {
    message: '我是父组件传来的'
  },
}
</script>

 子组件:children.vue :

<template>
    <childB></childB>
    <div>1 + {{message}}</div>
</template>

<script>
import childB from './childB.vue';
export default {
    name: 'child',
    components: {
        childB
    },
    inject: ['message'],
}
</script>

 子组件:childB.vue :

<template>
    <div>2 + {{message}}</div>
</template>

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

注:

provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。Why?

5、$attrs 和$listeners 

  • $attrs: 包含了父作用域中不作为 prop 被识别的 attribute 绑定 (class 和 style 除外)
  • $listeners :  包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器(vue3中已移除)

(1) $attrs的使用如下

父组件parent.vue:

<template>
    <div class="myVue">
        <children :name="name" :age="age"></children>
    </div>
</template>
<script>
import children from './children'
export default {
  name: 'parent',
  data() {
    return {
        name: 'parent',
        age: 12
    }  
  },
  components: {
    children
  }
}
</script>

 子组件children.vue:

 可以看出父组件bind传过来的有name和age,但是name被props接收了,所以$attrs中只有age了

<template>
    <childB v-bind="$attrs" :test="test"></childB>
</template>

<script>
import childB from './childB.vue';
export default {
    data() {
        return {
            name: 'child',
            test:1 
        }
    },
    props: ['name'],
    components: {childB},
    created() {
        console.log(111,this.$attrs);  // 111 Proxy {age: 12, __vInternal: 1}
    } 
}
</script>

子组件childB.vue: 

 可以看出父组件bind传过来的有test和$attr(父组件的父组件中的age)

<template>
    <div></div>
</template>

<script>
export default {
    data() {
        return {
            name: 'childB'
        }
    },
    created() {
        console.log(222,this.$attrs);//222 Proxy {age: 12, test: 1, __vInternal: 1}
    }
}
</script>

二、兄弟组件之间传参

1、父组件中转

这个方式很好理解,但是比较麻烦,就是将某一子组件中的参数先通过v-on 与 $emit() 传给父组件,父组件再通过v-bind传给另一个子组件,相信大家都会,此处部分代码省略。

2、借助于eventBus事件总线,通过eventBus的方式传递数据

在自己喜欢的位置建立一个js文件,我这取名为bus.js,创建一个Vue的实例,让各个兄弟共用同一个事件机制,内容如下:

import Vue from 'vue'
export default new Vue()

在传递参数的兄弟组件 children.vue 中:

通过 Bus.$emit 将参数传给函数 funcBrother

<template>
  <div>
      <button @click="func">点击按钮向兄弟组件children传值</button>
  </div>
</template>

<script>
import Bus from '../bus'
export default {
  data () {
    return {
      x: 1
    }
  },
  methods: {
    func () {
      Bus.$emit('funcBrother', this.x++)
    }
  }
}
</script>
<style lang="less" scoped>
  div {
    font-size: 40px;
  }
  div:hover {
    cursor: pointer;
  }
</style>

 在接受的兄弟组件 brother.vue 中:

 通过 Bus.$on 接收传过来的值

<template>
 <div>
    第{{msg}}次
 </div>
</template>

<script>
import Bus from '../bus'
export default {
  data () {
    return {
      msg: 0
    }
  },
  created () {
    Bus.$on('funcBrother', (val) => {
      this.msg = val
    })
  }
}
</script>

3、直接把需要的参数放在 localStroage 或 sessionStroage

这个就是存入取出的工作,同时注意两者的区别,可见LocalStorage和sessionStorage的区别。但是用这种方式存储的话一定要注意几个问题:

  • 存储空间有限,不需要永久存储的东西在使用完毕之后及时清除
  • 由于是全局使用,所以要合理使用命名空间,防止key重复污染等问题,最后事先约定好,或者写在README里
  • 可能在多个组件中都需要存入取出操作,所以耦合度高,在修改时就很麻烦,最后封装成函数处理

4、vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。Vuex 解决了多个视图依赖于同一状态来自不同视图的行为需要变更同一状态的问题。

具体使用可见vuex.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值