详解Vue3的七种组件通信方式

目录
  • 写在前面
  • 举一个栗子
  • Props方式
  • emit方式
  • v-model方式
  • refs方式
  • provide/inject方式
  • 事件总线
  • 状态管理工具

写在前面

本篇文章是全部采用的<script setup>这种组合式API写法,相对于选项式来说,组合式API这种写法更加自由,具体可以参考Vue文档对两种方式的描述。

本篇文章将介绍如下七种组件通信方式:

  • props
  • emit
  • v-model
  • refs
  • provide/inject
  • eventBus
  • vuex/pinia(状态管理工具)

开始搞事情~

举一个栗子

俗话说的好,学习不写demo,那就是耍流氓~

本篇文章将围绕下面这个demo,如下图所示:

上图中,列表和输入框分别是父子组件,根据不同传值方式,可能谁是父组件谁是子组件会有所调整。

Props方式

Props方式是Vue中最常见的一种父传子的一种方式,使用也比较简单。

根据上面的demo,我们将数据以及对数据的操作定义在父组件,子组件仅做列表的一个渲染;

父组件代码如下:

<template>
  <!-- 子组件 -->
  <child-components :list="list"></child-components>
  <!-- 父组件 -->
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript', 'HTML', 'CSS'])
const value = ref('')
// add 触发后的事件处理函数
const handleAdd = () => {
  list.value.push(value.value)
  value.value = ''
}
</script>

子组件只需要对父组件传递的值进行渲染即可,代码如下:

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in poops.list" :key="i">{{ i }}</li>
  </ul>
</template>
<script setup>
import { defineProps } from 'vue'
const poops = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
})
</script>

emit方式

emit方式也是Vue中最常见的组件通信方式,该方式用于子传父;

根据上面的demo,我们将列表定义在父组件,子组件只需要传递添加的值即可。

子组件代码如下:

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleSubmit" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineEmits } from 'vue'
const value = ref('')
const emits = defineEmits(['add'])
const handleSubmit = () => {
  emits('add', value.value)
  value.value = ''
}
</script>

在子组件中点击【添加】按钮后,emit一个自定义事件,并将添加的值作为参数传递。

父组件代码如下:

<template>
  <!-- 父组件 -->
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
  <!-- 子组件 -->
  <child-components @add="handleAdd"></child-components>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript', 'HTML', 'CSS'])
// add 触发后的事件处理函数
const handleAdd = value => {
  list.value.push(value)
}
</script>

在父组件中只需要监听子组件自定义的事件,然后执行对应的添加操作。

v-model方式

v-model是Vue中一个比较出色的语法糖,就比如下面这段代码

<ChildComponent v-model:title="pageTitle" />

就是下面这段代码的简写形势

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />

v-model确实简便了不少,现在我们就来看一下上面那个demo,如何用v-model实现。

子组件

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineEmits, defineProps } from 'vue'
const value = ref('')
const props = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
})
const emits = defineEmits(['update:list'])
// 添加操作
const handleAdd = () => {
  const arr = props.list
  arr.push(value.value)
  emits('update:list', arr)
  value.value = ''
}
</script>

在子组件中我们首先定义propsemits,然后添加完成之后emit指定事件。

update:*是Vue中的固定写法,*表示props中的某个属性名。

父组件中使用就比较简单,代码如下:

<template>
  <!-- 父组件 -->
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
  <!-- 子组件 -->
  <child-components v-model:list="list"></child-components>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript', 'HTML', 'CSS'])
</script>

refs方式

在使用选项式API时,我们可以通过this.$refs.name的方式获取指定元素或者组件,但是组合式API中就无法使用哪种方式获取。如果我们想要通过ref的方式获取组件或者元素,需要定义一个同名的Ref对象,在组件挂载后就可以访问了。

示例代码如下:

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in childRefs?.list" :key="i">
      {{ i }}
    </li>
  </ul>
  <!-- 子组件 ref的值与<script>中的保持一致 -->
  <child-components ref="childRefs"></child-components>
  <!-- 父组件 -->
</template>
<script setup>
import { ref } from 'vue'
import ChildComponents from './child.vue'
const childRefs = ref(null)
</script>

子组件代码如下:

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineExpose } from 'vue'
const list = ref(['JavaScript', 'HTML', 'CSS'])
const value = ref('')
// add 触发后的事件处理函数
const handleAdd = () => {
  list.value.push(value.value)
  value.value = ''
}
defineExpose({ list })
</script>

setup组件默认是关闭的,也即通过模板ref获取到的组件的公开实例,不会暴露任何在**<script setup>中声明的绑定。如果需要公开需要通过****defineExpose**** API暴露**。

provide/inject方式

provideinject是Vue中提供的一对API,该API可以实现父组件向子组件传递数据,无论层级有多深,都可以通过这对API实现。示例代码如下所示:

父组件

<template>
  <!-- 子组件 -->
  <child-components></child-components>
  <!-- 父组件 -->
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, provide } from 'vue'
import ChildComponents from './child.vue'
const list = ref(['JavaScript', 'HTML', 'CSS'])
const value = ref('')
// 向子组件提供数据
provide('list', list.value)
// add 触发后的事件处理函数
const handleAdd = () => {
  list.value.push(value.value)
  value.value = ''
}
</script>

子组件

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
</template>
<script setup>
import { inject } from 'vue'
// 接受父组件提供的数据
const list = inject('list')
</script>

事件总线

Vue3中移除了事件总线,但是可以借助于第三方工具来完成,Vue官方推荐mitttiny-emitter

在大多数情况下不推荐使用全局事件总线的方式来实现组件通信,虽然比较简单粗暴,但是长久来说维护事件总线是一个大难题,所以这里就不展开讲解了,具体可以阅读具体工具的文档

状态管理工具

VuexPinia是Vue3中的状态管理工具,使用这两个工具可以轻松实现组件通信,由于这两个工具功能比较强大,这里就不做展示了,具体可以查阅文档

以上就是详解Vue3的七种组件通信方式的详细内容,更多关于Vue3组件通信方式的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue 组件通信的多种方式

    目录 前言 一.vuex 二.eventBus 三.props/emit 四.$parent/$children 五.$attrs/$listeners 六.provide/inject 前言 在vue中,​ 组件的关系不外乎以下三种: 组件是需要通信的,在开发中,常用到的通信方式有:vuex.eventBus.以及props与emit.$parent与$children,除此之外,还有provide与inject.$attrs与$listeners等. 一.vuex 这个相信大家用的很多了,简

  • vue实现组件通信的八种方法实例

    目录 1.props 父组件--->子组件通信 2.$emit 子组件--->父组件传递 3.bus(事件总线) 兄弟组件通信 4.$parent.$children 直接访问组件实例 5.$refs 6.provide/inject(提供/注入) 多组件或深层次组件通信 7.slot(slot-scope作用域插槽) 子元素-->父元素(类似于通信) 8.vuex状态管理 总结 对于vue来说,组件之间的消息传递是非常重要的,下面是我对组件之间消息传递的常用方式的总结 1.props

  • Vue组件通信方法案例总结

    目录 一.父组件向子组件传值(props) 二.子组件向父组件传值($emit) 三.兄弟组件传值(EventBus) 1. 初始化(new Vue()) 2. 发送事件($emit()) 3. 接收事件($on()) 4. 移除事件监听者 四.Vuex 一.父组件向子组件传值(props) 步骤: 在父组件中通过 v-bind 将数据传给子组件 在子组件中通过 props 接收父组件传递过来的数据 <div id="app"> <!-- 1.通过 v-bind 将数

  • Vue3的7种种组件通信详情

    目录 1.Vue3 组件通信方式 2.Vue3 通信使用写法 2.1 props 2.2 $emit 2.3 expose / ref 2.4 attrs 2.5 v-model 2.6 provide / inject 2.7 Vuex 1.Vue3 组件通信方式 props $emit expose / ref $attrs v-model provide / inject Vuex 2.Vue3 通信使用写法 2.1 props 用 props 传数据给子组件有两种方法,如下 方法一:混合

  • vue中组件通信详解(父子组件, 爷孙组件, 兄弟组件)

    vue中我们常常用到组件. 那么组件总体可以分为如下的几种关系. 父子组件, 爷孙组件, 兄弟组件. 这几种组件之间是如何通信的呢? 父子组件通信 根据vue中的文档可知, 组件的props属性用于接收父组件传递的信息. 而子组件想要向父组件传递信息, 可以使用$emit事件. 我们定义两个组件, 一个为父组件名为father, 另外一个为子组件child. 子组件通过props属性接收父组件传递的值, 这个值为fname, 是父组件的名字. 点击子组件的按钮, 触发toFather事件, 向父

  • 解决父子组件通信的三种Vue插槽

    目录 前言 环境准备 Category组件 App组件 一.默认插槽 二.具名插槽 三.作用域插槽 总结 前言 插槽可以说是 Vue 中非常重要的一部分吧,在我学习和练习的过程中,当组件搭配着插槽一起使用的时候,会发挥的更好一些.更多时候也会更加方便. 今天介绍Vue中三种插槽吧:默认插槽.具名插槽.作用域插槽. 环境准备 先搭个初始环境给大家看看哈.一步一步讲完这个插槽. 就是写了一个类别组件,分别渲染这三种数据. Category组件 <template> <div class=&q

  • 详解Vue3的七种组件通信方式

    目录 写在前面 举一个栗子 Props方式 emit方式 v-model方式 refs方式 provide/inject方式 事件总线 状态管理工具 写在前面 本篇文章是全部采用的<script setup>这种组合式API写法,相对于选项式来说,组合式API这种写法更加自由,具体可以参考Vue文档对两种方式的描述. 本篇文章将介绍如下七种组件通信方式: props emit v-model refs provide/inject eventBus vuex/pinia(状态管理工具) 开始搞

  • Vue2和Vue3的10种组件通信方式梳理

    目录 props emit attrs和listeners provide/inject parent/children expose&ref EventBus/mitt 写在最后 Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异:本文将通过选项式API 组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式. 其中将要实现的通信方式如下表所示: 方式 Vue2 Vue3 父传子 props props 子传父 $emit emits 父传子

  • Vue3的10种组件通信方式总结

    目录 引言 Props emits expose/ref Non-Props 单个根元素的情况 多个元素的情况 v-model 单值的情况 多个v-model绑定 v-model修饰符 插槽slot 默认插槽 具名插槽 作用域插槽 provide/inject 总线bus getCurrentInstance Vuex 安装 使用 State Getter Mutation Action Module Pinia 安装 注册 在组件中使用 啰嗦两句 mitt.js 安装 使用 总结 引言 本文讲

  • 详解Vue的七种传值方式

    1,父传子 子组件中定义props字段,类型为数组(如果需要限制字段值类型,也可以定义为对象的形式).如下图的例子,父组件挂载子组件HelloWorld,在组件标签上给title赋值,子组件HelloWorld定义props,里面有一个值是title,这样子组件就可以使用父组件的值了. 父组件 <template> <div> <HelloWorld :title="msg" /> </div> </template> <

  • 详解vue3+quasar弹窗的几种方式

    目录 1. 鼠标悬浮时的提示(Quasar Tooltip组件) 2. 点击某按钮后出现自定义的弹窗 3. 弹出操作列表/菜单列表(quasar Qmenu组件) 4. 弹出一个操作确认框(Quasar Dialog插件) 5. 弹出一个提示框(Quasar Notify插件) 6. Quasar QPopupProxy 1. 鼠标悬浮时的提示(Quasar Tooltip组件) quasar tooltip组件当希望将鼠标悬停在目标元素上会显示提示消息时,可以使用html中的title属性,但

  • 详解vue3中组件的非兼容变更

    函数式组件 functional attribute 在单文件组件 (SFC) <template> 已被移除 { functional: true } 选项在通过函数创建组件已被移除 // 使用 <dynamic-heading> 组件,负责提供适当的标题 (即:h1,h2,h3,等等),在 2.x 中,这可能是作为单个文件组件编写的: // Vue 2 函数式组件示例 export default { functional: true, props: ['level'], re

  • 详解Vue3 Composition API中的提取和重用逻辑

    Vue3 Composition API可以在大型项目中更好地组织代码.然儿,随着使用几种不同的选项属性切换到单一的setup 方法,许多开发人员面临的问题是-- 这会不会更混乱,因为一切都在一个方法中 乍一看可能很容易,但是实际上只需要花一点点时间来编写可重用的模块化代码. 让我们来看看如何做到这一点. 问题 Vue.js 2.x 的 Options API 是一种非常直观的分隔代码的方法 export default { data () { return { articles: [], se

  • 详解Vue3 Teleport 的实践及原理

    Vue3 的组合式 API 以及基于 Proxy 响应式原理已经有很多文章介绍过了,除了这些比较亮眼的更新,Vue3 还新增了一个内置组件: Teleport.这个组件的作用主要用来将模板内的 DOM 元素移动到其他位置. 使用场景 业务开发的过程中,我们经常会封装一些常用的组件,例如 Modal 组件.相信大家在使用 Modal 组件的过程中,经常会遇到一个问题,那就是 Modal 的定位问题. 话不多说,我们先写一个简单的 Modal 组件. <!-- Modal.vue --> <

  • 详解vue3的沙箱机制

    前言 vue3 沙箱主要分两种 浏览器编译版本,浏览器版本是使用with语法加上proxy代理拦截 本地预编译版本,通过在模版预编译阶段转换阶段,使用转换插件transformExpression将非白名单标识符挂在在组件代理对象下 浏览器编译版本 render 函数编译结果 <div>{{test}}</div> <div>{{Math.floor(1)}}</div> to const _Vue = Vue; return function render

  • 详解vue3沙箱机制

    目录 前言 浏览器编译版本 本地预编译版本 总结 参考 前言 vue3 沙箱主要分两种 浏览器编译版本,浏览器版本是使用with语法加上proxy代理拦截 本地预编译版本,通过在模版预编译阶段转换阶段,使用转换插件transformExpression将非白名单标识符挂在在组件代理对象下 浏览器编译版本 render 函数编译结果 <div>{{test}}</div> <div>{{Math.floor(1)}}</div> to const _Vue =

随机推荐