前置

做大小 vue 项目都离不开组件通讯, 自己也收藏了很多关于 vue 组件通讯的文章. 今天自己全部试了试, 并查了文档, 在这里总结一下并全部列出, 都是简单的例子. 如有错误欢迎指正.

温馨提示: 下文没有列出 vuex, vuex 也是重要且先进的组件通讯方式.

props

props 可以是数组或对象,用于接收来自父组件的数据。对象允许配置高级选项,如类型检测、自定义验证和设置默认值。

Son.vue

export default {
  props: {
    text: {
      type: String,
      required: true,
    },
  },

  mounted() {
    console.log(this.text) // 我是父组件提供给子组件的值
  },
}

App.vue

<template>
  <Son text='我是父组件提供给子组件的值'/>
</template>

<script>
import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
    Son,
  }
},
</script>

$emit

$emit 触发当前实例上的事件。附加参数都会传给监听器回调。

Son

export default {
  mounted() {
    this.$emit('customFunc', '我是子组件传给父组件的值')
  },
}

App

<template>
  <Son v-on:customFunc="fatherFunc" />
</template>

<script>
import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
    Son,
  },

  methods: {
    fatherFunc(value) {
      console.log(value) // 我是子组件传给父组件的值
    },
  },
}
</script>

.sync @update

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。推荐以 update:myPropName 的模式触发事件取而代之。

Son

export default {
  mounted() {
    this.$emit("update:text", '我是子组件传给父组件的值')
  }
}

App

<template>
  <Son :text.sync='text'/>
</template>

<script>
import Son from "./components/dispatch/Son"
export default {
  data() {
    return {
      text: ''
    }
  },
  mounted() {
    console.log(this.text); // 我是子组件传给父组件的值
  }
}
</script>

上面这种写法是对如下方式的简写, 或者称之为语法糖.

Son

export default {
    mounted () {
        this.$emit('update:text','我是子组件传给父组件的值')
    }
}

App

 <Son @update:text="v => (this.value = v)" />

 import Son from "./components/dispatch/Son"
 export default {
  mounted() {
    console.log(this.value) // 我是子组件传给父组件的值
  }
}

v-model

自定义事件也可以用于创建支持 v-model 的自定义输入组件。

<input v-model="searchText">

等价于:

<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value"
>

Son

<template>
  <input
    v-bind:value="value"
    v-on:input="$emit('input', $event.target.text)"
  />
</template>

<script>
export default {
    data() {
        return {
            value: '我是子组件传给父组件的值',
        }
    }
}
</script>

App

<template>
  <Son v-model="text" />
</template>

<script>
import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
    Son,
  }
}
</script>

$parent $childred

$parent

父实例,如果当前实例有的话。

$children

当前实例的直接子组件。需要注意 $children 并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。

App

export default {
  data() {
    return {
      value: '我是父组件的值',
    }
  },

Son

export default {
  mounted: {
      console.log(this.$parent.value) // 我是父组件的值
      this.$parent.value = 666
      console.log(this.$parent.value) // 666
  },
}

1.使用 $parent 配合 $emit 实现跨级向上传值. 简单封装一下即可实现:

main.js

Vue.prototype.$dispatch = function(event, value) {
  let parent = this.$parent
  while (parent) {
    parent.$emit(event, value)
    parent = parent.$parent
  }
}

这样使用: this.$dispatch('event',value)

2.使用 $children 配合 $emit 实现向下传值. 简单封装一下即可实现:

Vue.prototype.$broadcast = function(event, value) {
  const broadcast = children => {
    children.forEach(child => {
      child.$emit(event, value)
      if (child.$children) {
        broadcast(child.$children)
      }
    })
  }
  broadcast(this.$children)
}

这样使用: this.$broadcast('event',value)

$attrs

包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件(在创建高级别的组件时非常有用)。

App

<template>
  <Son :value1="123" :value2="456" />
</template>

import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
        Son,
  },
}

Son

<template>
  <div>{{$attrs}}</div>
</template>

<script>
export default {
  inheritAttrs: false,
}
</script>

$listener

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

App

<template>
  <Son @customFunc="fatherFunc"/>
</template>

<script>
import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
        Son,
  },
  methods: {
    fatherFunc() {
      console.log('666')
    },
  },
}
</script>

Son

<template>
  <button @click="$listeners.customFunc()">看</button>
</template>

如果子组件不使用这些方法,孙子组件使用,则可以使用 v-on="$listeners" 来传递给孙子组件这些方法,孙子组件使用时,同样使用 $listeners,以此类推.

$refs

一个对象,持有注册过 ref 特性的所有 DOM 元素和组件实例。

Son

export default {
  methods: {
    sonFunc() {
      console.log('我是子组件的值')
    },
  },
}

App

<template>
  <Son ref="sonref"/>
</template>

<script>
import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
        Son,
  },
  mounted() {
    this.$refs.sonref.sonFunc()
  },
}
</script>

控制台打印: 我是子组件的值

provide inject

provideinject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 Symbol 和 Reflect.ownKeys 的环境下可工作。

provide 和 inject 绑定并不是可响应的。这是 vue 刻意为之。但是如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

App

<template>
  <Son />
</template>

<script>
import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
        Son,
  },
  provide() {
    return {
      text: '我是父组件的值',
    }
  },
}
</script>

Son

export default {
  inject: ['text'],
  mounted() {
    console.log(this.text) // 我是父组件的值
  },
}

事件总线(EventBus)

EventBus 又称为事件总线。在 vue 中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此才需要更完善的 Vuex 作为状态管理中心,将通知的概念上升到共享状态层次。

App

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

<script>
import Son from './components/dispatch/Son'
export default {
  name: 'app',
  components: {
        Son,
  },
  mounted() {
    this.$EventBus.$emit('event', 'app.vue')
  },
}
</script>

Son

export default {
  mounted() {
    this.$EventBus.$on('event', function(v) {
      console.log(v)
    })
  },
}

Observable

让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。返回的对象可以直接用于渲染函数和计算属性内,并且会在发生改变时触发相应的更新。也可以作为最小化的跨组件状态存储器,用于简单的场景.

store.js

import Vue from 'vue'

export const store = Vue.observable({ text: '我是store里的' })
export const mutations = {
  setText(text) {
    store.text = text
  },
}

App

import { store, mutations } from '../store'
export default {
    mounted() {
      console.log(store.text) //我是store里的
      mutations.setText('我在App.vue中将你改变')
      console.log(store.text) //我在App.vue将你改变
  },
}

composition-api

  • provide()inject() 可以实现嵌套组件之间的数据传递。
  • 这两个函数只能在 setup() 函数中使用。
  • 父级组件中使用 provide() 函数向下传递数据。
  • 子级组件中使用 inject() 获取上层传递过来的数据。
  • 不限层级。

App

<template>
  <provideAndInject />
</template>

<script>
import { provide } from "@vue/composition-api"
import provideAndInject from "./components/provideAndInject"

export default {
  name: "app",
  components: {
    provideAndInject
  },
  setup() {
    // provide('数据名称', 要传递的数据)
    provide("customVal", "我是父组件向子组件传递的值");
  }
};
</script>

Son

<template>
  <h3>{{ customVal }}</h3>
</template>

<script>
import { inject } from "@vue/composition-api";

export default {
  setup() {
    //调用 inject 函数,通过指定的数据名称,获取到父级共享的数据
    const customVal = inject("customVal");

    return {
      customVal
    };
  }
};
</script>

父组件可以通过 ref 创建响应式数据通过 provide 共享给子组件.

欢迎补充. 如果对你有帮助, 点个赞再走吧.

vue 组件通讯方式到底有多少种 ?的更多相关文章

  1. Vue组件通讯黑科技

    Vue组件通讯 组件可谓是 Vue框架的最有特色之一, 可以将一大块拆分为小零件最后组装起来.这样的好处易于维护.扩展和复用等. 提到 Vue的组件, 相必大家对Vue组件之间的数据流并不陌生.最常规 ...

  2. vue组件定义方式,vue父子组件间的传值

    vue组件定义方式,vue父子组件间的传值 <!DOCTYPE html> <html lang="zh-cn"> <head> <met ...

  3. vue组件通讯之provide / inject

    什么是 provide / inject [传送门] vue的组件通讯方式我们熟知的有 props $emit bus vuex ,另外就是 provide/inject provide/inject ...

  4. vue组件通讯方法汇总(在不使用vuex的情况下)

    前三种是父子组件通讯,最后一种是平级组件.

  5. 到底有多少种智能指针(smart pointer)

    最近Qt的blog总结了到底有多少种smart pointer, 下面是一个简要的介绍: 1.   QPointer :提供对指针的保护,当一个指针被删除以后,再使用不会造成野指针或者指针溢出.比如 ...

  6. Vue组件间通信方式到底有几种

    1. 前言 Vue的一个核心思想就是组件化.所谓组件化,就是把页面拆分成多个组件 (component),每个组件依赖的 CSS.JavaScript.模板.图片等资源放在一起开发和维护.组件是资源独 ...

  7. Angular1.x组件通讯方式总结

    Angular1开发模式 这里需要将Angular1分为Angular1.5之前和Angular1.5两个不同的阶段来讲,两者虽然同属Angular1,但是在开发模式上还是有较大区别的.在Angula ...

  8. Vue组件通讯

    Vue最常用的组件通讯有三种:父->子组件通讯.子->父组件通讯,兄弟组件通讯.(template用的pug模板语法) 1.父->子组件通讯 父->子组件通讯,是通过props ...

  9. Angular1组件通讯方式总结

    这里需要将Angular1分为Angular1.5之前和Angular1.5两个不同的阶段来讲,两者虽然同属Angular1,但是在开发模式上还是有较大区别的.在Angular1.4及以前,主要是基于 ...

随机推荐

  1. less 的使用方法总结

    一. 安装和使用 LESS 1.1 安装 使用命令行安装 LESS npm install -g less 1.2 使用 less 有多种的使用方法,在这里我向大家介绍最常用的俩种方法. 第一种是直接 ...

  2. 谷歌Waymo估值700亿:自动驾驶迎来春天,但前路漫漫

    在经过近一年的法庭之争后,Waymo与Uber的自动驾驶专利权诉讼案于近日宣布和解.最终的结果,是Uber向Waymo支付0.34%股权(目前价值2.44亿美元).但事实上,与Uber的官司解决后,一 ...

  3. 网易与Google合作,于GDC开幕首日发布开源UI自动化测试方案

    [TechWeb报道]美西时间3月19日,在GDC开幕第一天的Google开发者专场,Google发布了一款由网易研发的UI自动化测试方案:Airtest Project. Google方面评价,这可 ...

  4. Linux USB 鼠标驱动程序详解(转)

    Linux USB 鼠标驱动程序详解 USB 总线引出两个重要的链表!一个 USB 总线引出两个重要的链表,一个为 USB 设备链表,一个为 USB 驱动链表.设备链表包含各种系统中的 USB 设备以 ...

  5. 连接器巨头Molex莫仕大裁员,CEO更迭

    序言:中美贸易战的大环境下,美国多方面限制对华出口电子科技,其中影响最大的莫过于限制芯片出口,中国本土芯片和电子产业也在蓬勃的发展.根据正能量电子了解连接器巨头MOLEX莫仕公司收入的1/3是来自于对 ...

  6. DotNet Core 使用 StackExchange.Redis 简单封装和实现分布式锁

    前言 公司的项目以前一直使用 CSRedis 这个类库来操作 Redis,最近增加了一些新功能,会存储一些比较大的数据,内测的时候发现其中有两台服务器会莫名的报错 Unexpected respons ...

  7. 《数字信号处理》课程实验2 – FIR数字滤波器设计

    一.FIR数字滤波器设计原理  本实验采用窗函数法设计FIR数字低通滤波器.我们希望设计的滤波器系统函数如下: \(H_{d}\left( e^{jw} \right) = \left\{ \begi ...

  8. C++对拍

    作为一名OIer,比赛时,对拍是必须的 不对拍,有时可以悔恨终身 首先,对拍的程序 一个是要交的程序 另一个可以是暴力.搜索等,可以比较慢,但是必须正确 下面是C++版对拍程序(C++ & c ...

  9. 学习Java技术哪家强

    https://github.com/CyC2018/CS-Notes https://github.com/Snailclimb/JavaGuide SpringBoot 之 配置文件优先级 htt ...

  10. 实验一 Linux系统与应用准备

    实验一 Linux系统与应用准备 项目 内容 作业归属 班级课程 作业要求 课程作业要求 学号-姓名 17041419-刘金林 作业学习目标 1.学习博客园软件开发者学习社区使用技巧和经验:2.学习M ...