详解vue组件之间的通信

说明:下面我总结了比较常用的vue组件之前通信的方式,最近准备面试,所以有些总结贴上来分享

props和$emit

只有父子关系才可以用这种方式,父组件向子组件传递参数用props,子向父传递使用触发$emit自定义事件

1.props

<!-- parent.vue, 可以传递`静态`的props和`动态`的props, 静态的参数只能是个String类型的,如果是其他类型的一定要记得加`:`来表示这是一个 js 表达式而不是一个字符串 -->
<Child :name="name" :age="18" address="xxxxx"></Child>
...
data () {
 return {
  name: 'marry'
 }
}

<!-- 传一个参数所有props, 虽然目前我没有这个需求,使用不带参数的 v-bind -->
<blog-post v-bind="post"></blog-post>
post: {
 id: 1,
 title: 'My Journey with Vue'
}
//等价于下面
<blog-post
 v-bind:id="post.id"
 v-bind:title="post.title"
></blog-post>

<!-- child.vue -->
...
//以字符串数组形式列出的 prop
props: ['name', 'age', 'address']

//prop验证, 当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告
//注意:以下类型不能写成'String'这种带引号的形式
props: {
 // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
 propA: Number,
 // 多个可能的类型
 propB: [String, Number],
 // 必填的字符串
 propC: {
  type: String,
  required: true
 },
 // 带有默认值的数字
 propD: {
  type: Number,
  default: 100
 },
 // 带有默认值的对象
 propE: {
  type: Object,
  // 对象或数组默认值必须从一个工厂函数获取
  default: function () {
  return { message: 'hello' }
  }
 },
 // 自定义验证函数
 propF: {
  validator: function (value) {
  // 这个值必须匹配下列字符串中的一个
  return ['success', 'warning', 'danger'].indexOf(value) !== -1
  }
 }
}
//注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

2.$emit

<!-- parent.vue -->
<Child @my-event="myEvent"></Child>
...
methods: {
 myEvent(name){
 this.name = name
 }
}

<!-- child.vue -->
<div>
 <button @click="$emit('my-event', name)"></button>
</div>
//使用自定义事件将子组件的值抛给父组件

中央事件总线 bus

用于解决跨级和兄弟组件通信问题,巧妙的使用一个公共的vue实例,利用$on, $emit, $off(移除自定义事件监听器)

方法一:

可以在main.js中,在Vue的原型上挂载一个公共的Vue实例 $bus,这样全局任何一个地方都可以使用

Vue.prototype.$bus = new Vue()

然后在需要的地方注册自定义事件和接收参数的回调函数

this.$bus.$on('changeName', name => {
 this.name = name
})

在需要改变的时候触发事件并抛出参数

this.$bus.$emit('changeName', 'wzj')

方法二:

定义一个util.js文件

import Vue from 'vue'

const bus = new Vue()
export default bus

在需要用到bus的文件中引入

import bus from '../util' //文件路径不一定

//在一个文件定义事件
bus.$on('changeName', name => {
 this.name = name
})

//另一个文件抛出参数
bus.$emit('changeName', 'wzj')

vuex

对于项目比较复杂,多组件共享状态,不同层级需要通信

核心概念:

state, getter, mutation, action, module

//store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export dafault new Vuex.Store({
 state: {
 name: '',
 age: 0
 },
 getters: {
 tranName(state){
  return 'name: ' + state.name
 }
 },
 mutations: {
 changeName(state, name){
  state.name = name
 }
 },
 /*Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters */
 actions: { //异步函数,但还是要通过提交commit触发mutations函数操作state
 changeName(context, name){
  context.commit('changeName', name)
 }
 },
 modules: {}
})

在组件中使用

方法一:

//访问state属性
this.$store.state.name
//访问getters属性
this.$store.getters.tranName
//访问mutations
this.$store.commit('changeName', 'wzj')
//访问actions
this.$store.dispatch('changeName', 'wzj')

方法二:使用辅助函数映射到本地,这里只列举了简便的方式,更多查阅官网吧

import {mapState, mapGetters, mapMutations, mapActions} from 'vuex'
//state 和 getters 映射到本地的computed属性中,作为计算属性使用
computed: {
 ...mapState(['name', 'age']),
 ...mapGetters(['tranName'])
}

//mutations 和 actions
methods: {
 // 将 `this.changeName()` 映射为 `this.$store.commit('changeName')`
 ...mapMutations(['changeName'])
 // 将 `this.changeName()` 映射为 `this.$store.dispatch('changeName')`
 ...mapActions(['changeName'])
}

$attrs 和 $listeners

父组件与后代组件,用以上方法有点大材小用或者第一种有些不方便

  • $attrs 包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 ( class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。
  • $listeners 包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

例子:

//app.vue
<div>
 <One name="wzj" :age="age" address="xian" @changeAge="changeAge"></One>
</div>
...
data(){
 return {
 age: 10
 }
},
methods: {
 changeAge(age){
 this.age = age
 }
}

//one.vue
<div>
 <div>姓名:{{ name }}</div>
 <div>年龄:{{ age }}</div>
 <Two v-bind="$attrs" v-on="$listeners"></Two>
 <button @click="change">点我2</button>
</div>
...
props: ['name', 'age'],

//two.vue
<div>
 <div>{{ address }}</div>
 <button @click="change">点我2</button>
</div>
...
props: ['address'], //用$attrs传递到最后的属性,在使用的时候还是要声明props
methods: {
 change(){
 this.$emit('changeAge', 30)
 }
}

理解:其实祖先组件的属性和事件还是一层层往下传,不过用$attrs 和 $listeners优化和简便了传递过程中书写,而且在传递的过程中,任何一个声明了 $listeners的组件都可以触发里面的所有事件,而声明了$attrs的组件只能使用之前未用props声明的剩下的属性。

以上就是vue组件之间的通信的详细内容,更多关于vue 组件通信的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue 解决兄弟组件、跨组件深层次的通信操作

    兄弟组件之间的通信同样是在项目中经常会遇到的组件间的通信问题之一, 这种问题的最根本方法就是: 把兄弟组件内部的变量提升到一个中央仓库. 借助父级组件链式交互 使子组件1 通过 $emit 通知父级, 父级再通过响应 子组件1 的事件去触发子组件2的事件,这样的链式操作,在子组件不多的时候,但是一个不错的解决方法 子组件1 <template> <div> <p @click="$emit('fromFirst','来自A组件')">first组件&

  • Vue组件间的通信pubsub-js实现步骤解析

    本文介绍使用发布订阅的方式进行vue组件间的通信 我认为这种方式比较自由, 不存在组件间的关系问题 1. 首先安装pubsub-js npm install --save pubsub-js 2. 订阅方组件 import PubSub from 'pubsub-js' mounted(){ // 执行异常代码 // 订阅消息 PubSub.subscribe('deleteTodo',(msg,index)=>{ this.deleteTodo(index) // 调用deleteTodo方法

  • Vue.js组件通信之自定义事件详解

    组件通信 从父组件向子组件通信,通过props传递数据就可以了,但Vue组件通信的场景不止有这一种,归纳起来,组件之间的通信可以用下图来表示: 自定义事件 当子组件需要向父组件传递数据时,就要用到自定义事件.子组件用**$ emit()来触发事件**,父组件用**$ on()**来监听子组件的事件. 父组件也可以直接在子组件的自定义标签上使用v-on来监听子组件触发的事件. <!DOCTYPE html> <html lang="en"> <head>

  • vue中组件通信的八种方式(值得收藏!)

    前言 之前写了一篇关于vue面试总结的文章, 有不少网友提出组件之间通信方式还有很多, 这篇文章便是专门总结组件之间通信的 vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢? 首先我们需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式, 就好像过年回家,坐着一屋子的陌生人,相互之间怎么称呼,这时就需要先知道自己和他们之间是什么样的关系. vue组件中关系说明: 如上图所示, A与B.A与C.B与D.C与E组件之间

  • vue.js使用v-model实现父子组件间的双向通信示例

    本文实例讲述了vue.js使用v-model实现父子组件间的双向通信.分享给大家供大家参考,具体如下: <template> <div> 这是主页面 <h1> {{num}}</h1> <button @click="handleMins">-1</button> <hr> <!-- 作者:786905664@qq.com 时间:2017-09-24 描述:局部组件 --> <com

  • Vue组件通信入门之Provide和Inject机制

    前言 Vue中父组件到子组件的通信主要由子组件的props属性实现.但是在一些情况下,父组件无法直接向子组件的props传值.比如子组件通过父组件的slot进入父组件,父组件根本不知道子组件是谁,更不用说用子组件的props了.这时应该怎么办呢?Vue在2.2.0版本引入了provide与inject,正好适合处理这一情况. 什么是provide与inject 用文档的话说: provide/inject需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下

  • vue 组件间的通信之子组件向父组件传值的方式

    父组件向子组件传值:父组件通过属性向下传值的方式和子组件通信: 使用步骤: 定义组件:现有自定义组件com-a.com-b,com-a是com-b的父组件: 准备获取数据:com-b要获取父组件data中的name属性: 在<com-b :name="name"></com-b> 使用v-bind 绑定name属性,红色部分为属性名称,可以随意写. 在子组件定义部分里添加选项,值是个字符串数组 props:['name'],将上边红色的属性名称写在这里: 之后就

  • vuejs中父子组件之间通信方法实例详解

    本文实例讲述了vuejs中父子组件之间通信方法.分享给大家供大家参考,具体如下: 一.父组件向子组件传递消息 // Parent.vue <template> <div class="parent"> <v-child :msg="message"></v-child> </div> </template> <script> import VChild from './child.v

  • 详解利用eventemitter2实现Vue组件通信

    概述 当两个组件之间没有任何父子关系时,利用Vue标准的props传值和emit触发事件无法解决他们之间通信的问题.最近做的项目使用的是eventemitter2,来实现不相关组件之间的通信.这篇文章分享的是我对eventemitter2使用的总结和体会. eventemitter2的npm文档大家可以看eventemitter2介绍.它是node.js提供的事件接口.安装如下 npm install --save eventemitter2 模块的EventEmitter2属性是一个构造函数,

  • vue element-ui table组件动态生成表头和数据并修改单元格格式 父子组件通信

    父组件 定义表头和表内容 data(){ return{ // 表格数据 tableColumns: [], // 表头数据 titleData:[], } } 引入并注册子组件 import TableComponents from "../../components/table/table"; //注册子组件table components: { tableC: TableComponents }, 获取表头和表内容数据.(真实数据应该是从接口获取的,由于是测试数据这里我先写死)

随机推荐