vue 组件之间传值几种方式

vue 组件之间传值几种方式

今天说一下 vue3 的组件间传值,学习过 vue2 的宝子们肯定知道,组件传值是 vue 项目开发过程中必不可少的功能场景,在 vue2 里面有很多传值的方式,vue3 的传值方式呢,在这里稍微整理总结一下,但是不是很全,大家交流补充哦。

Vue2

1. 父组件

<template>
  <div>
    <children :title="title" @getChildren="getChildren"></children>
  <-- 父组件通过 @监听事件名称="触发的方法"来进行监听 -->
    <div>子组件说: {
   
   { childrenAsk }}</div>
  </div>
</template>
  
<script>
  import children from "./children.vue"
  export default {
      
      
    data() {
      
      
      return {
      
      
        title: "我是父组件传过来的值",
        childrenAsk: ""
      }
    },
    methods: {
      
      
      getChildren(val) {
      
      
        this.childrenAsk = val
      }
    }
  }
</script>

2. 子组件

<template>
  <div>
    <div>父组件传过来的值: {
   
   { title }}</div>
    <button @click="askToFather">点击发送给父组件</button>
  </div>
</template>
<script>
  export default {
      
      
    props: {
      
      
      title: {
      
      
        type: String
      }
    },
    data() {
      
      
      return {
      
      
        askMsg: "这是我给父组件说的话"
      }
    },
    methods: {
      
      
      askToFather() {
      
      
        this.$emit("getChildren", this.askMsg)
      }
    }
  }
</script>

3. 兄弟组件

就是创建一个事件中心,相当于中转站,可以用它来传递和接收事件
1.创建全局空 Vue 实例: eventBus

import Vue from 'vue';
const eventBus = new Vue();
export default  eventBus;

2.具体页面使用 $emit 发布事件 — 传递值

import eventBus from '@/eventBus'
eventBus.$emit('send','hello')

3.具体页面使用 $on 订阅事件 — 接收组件值

import eventBus  from  '@/eventBus'
eventBus.$on('send',mes=>{
    
    
	console.log(msg) //输出 hello
})

注意:

$on 先进行监听,一旦 $emit 发布事件后所有组件都可以 $on 监听到事件。所以传递参数的时候一定已经先进行了监听才能得到参数。比如在父组件中 $emit 事件放在mounted钩子函数中,等待子组件创建并 $on 开始监听事件后再去触发 $emit 发布事件。

4.$off() 移除事件监听

import eventsBus from '@/eventBus
eventBus.$off('send')

vue3

对比vue2来看,vue发生了不小的变化,通过ref,或者reactive实现数据的响应式
在vue2中,子组件向父组件传值通过this.$emit的形式实现,
setup 代替了 beforeCreate 和 Created setup 会在beforeCreate 之前调用
vue3中setup 接收了props 和 context 两个参数,props 接收当前组件props选择的值,即获取父组件传递过来的参数,接收参数后,return出去就可以在模板中使用
contex 接收一个上下文对象,该对象中包含了一些vue2 中需要通过 this 才能访问到的属性

子组件向父组件传值核心的部分是emit事件,子组件绑定一个emit触发事件,父组件监听事件就可以达到子组件向父组件传值的目的。

1. 父组件

<template>
  <div style="color: aqua">父组件</div>
  <div>子组件对我说:{
   
   { children_msg }}</div>
  <children :title="msg" @listen="listenToChildren"></children>
  {
   
   { value }}
</template>
<script lang="ts">
import children from "@/views/component_emit/children.vue"
import {
      
       defineComponent, ref } from "vue"
export default defineComponent({
      
      
  components: {
      
      
    children,
  },
  name: "father",
  setup() {
      
      
    let msg = "我是父组件"
    let children_msg = ref("") // ref的作用是实现响应式, 如果没有ref则不能实现响应式(引用数据类型用reactive)
    let listenToChildren = (val) => {
      
      
      children_msg.value = val // 使用ref包裹的数据,需要通过.value的形式访问他的值
    }
    return {
      
      
      msg,
      children_msg,
      listenToChildren,
    }
  },
})
</script>
<style></style>

2. 子组件

<template>
  <div style="color: brown">子组件</div>
  <!-- 父传子使用方法和vue2相同 -->
  <div>父组件传过来的值为:{
   
   { title }}</div>
  <button @click="sayToFather">向父组件说话</button>
</template>
<script lang="ts">
import {
      
       defineComponent } from "vue"
export default defineComponent({
      
      
  name: "children",
  props: {
      
      
    title: {
      
      
      type: String,
    },
  },
  setup(props, context) {
      
      
    // context作用是获取上下文对象,
    // 如果setup写法为setup(props, { emit })的方式的话,下面的context可以省略
    const sayToFather = () => {
      
      
      const ask = "我是子组件,我对父组件说话"
      context.emit("listen", ask)
    }
    return {
      
      
      sayToFather,
    }
  },
})
</script>
<style></style>

3. 兄弟传值

在 Vue3 中,Vue 不再是构造函数,而是 Vue.createApp({}) 返回一个没有 o n 、 on、 onemit 和 $once 方法的对象。

根据官方文档 Vue 3 迁移指南所建议的,我们可以使用 mitttiny-emitter 库在组件之间调度事件。

1.安装依赖     yarn add mitt 或 npm install mitt
2.用法
与 Vue2 一样,封装为 myBus.js:

import mitt from 'mitt'
export default mitt()

或者,也可以定义为全局变量:

import {
    
     createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt'
 
const app = createApp(App)
app.config.globalProperties.emitter = mitt()

然后封装一个 hooks

// src/hooks/useEmitter.js
import {
    
     getCurrentInstance } from 'vue'
 
export default function useEmitter() {
    
    
  const internalInstance = getCurrentInstance()
  const emitter = internalInstance.appContext.config.globalProperties.emitter
 
  return emitter
}

当然,为了方便管理,你也可以在需要用到的地方单独引入 mitt。
示例:假设我们有一个 sidebar 和 header,其中包含一个关闭/打开侧栏的按钮,我们需要该按钮来切换侧边栏展开或关闭。

//header 点击传递值
<template>
  <button @click="todoSidebar">todoSidebar</button>
</template>
<script setup>
  import {
    
     ref } from 'vue'
  import useEmitter from '@/hooks/useEmitter'
 
  const sidebarOpen = ref(true)
  const emitter = useEmitter()
 
  const toggleSidebar = () => {
    
    
    sidebarOpen.value = !sidebarOpen.value
    emitter.emit('todo-sidebar', sidebarOpen.value)
  }
</script>
// sider 接收值
<template>
  <aside class="sidebar" :class="{'sidebar--toggled': !isOpen}">
    {
    
    {
    
     isOpen }}
  </aside>
</template>
<script setup>
  import {
    
     ref, onMounted } from 'vue'
  import useEmitter from '@/hooks/useEmitter'
 
  const isOpen = ref(true)
  const emitter = useEmitter()
 
  onMounted(() => {
    
    
    emitter.on('todo-sidebar', (isOpen) => {
    
    
      isOpen.value = isOpen
    })
  })
</script>

猜你喜欢

转载自blog.csdn.net/weixin_49609457/article/details/125679873