Several ways to pass values between vue components

Several ways to pass values ​​between vue components

Let’s talk about value passing between vue3 components today. Those who have studied vue2 must know that component value passing is an indispensable functional scenario in the development process of vue projects. There are many ways to pass values ​​in vue2, and vue3’s value passing As for the method, I will summarize it a little here, but it is not very comprehensive. Please share and add.

View 2

1. Parent component

<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. Subcomponents

<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. Sibling components

It is to create an event center, which is equivalent to a transfer station, which can be used to transmit and receive events
1. Create a global empty Vue instance: eventBus

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

2. Specific pages use $emit to publish events—passing values

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

3. Specific pages use $on to subscribe to events—receive component values

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

Notice:

$on listens first, and once $emit publishes the event, all components can listen to the event with $on. So when passing parameters, you must have listened first to get the parameters. For example, in the parent component, the $emit event is placed in the mounted hook function, and the $emit release event is triggered after the child component is created and $on starts listening to the event.

4. $off() remove event listener

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

view 3

Compared with vue2, vue has undergone a lot of changes. Responsive data is realized through ref or reactive.
In vue2, the value transfer from child components to parent components is realized in the form of this.$emit, and
setup replaces beforeCreate and Created setup It will call the setup in vue3 before beforeCreate
to receive the two parameters of props and context. props receives the value selected by the current component props, that is, obtains the parameters passed by the parent component. After receiving the parameters, you can use the context in the template to receive
a The context object, which contains some properties that need to be accessed through this in vue2

The core part of the child component passing value to the parent component is the emit event. The child component binds an emit trigger event, and the parent component listens to the event to achieve the purpose of the child component passing the value to the parent component.

1. Parent component

<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. Subcomponents

<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. Brother pass value

In Vue3, Vue is no longer a constructor, but Vue.createApp({}) returns a function without on, on,An object with on , emit , and $once methods.

As suggested by the official documentation Vue 3 Migration Guide, we can use mitt or tiny-emitter library to dispatch events between components.

1. Installation depends on yarn add mitt or npm install mitt
2. Usage
Same as Vue2, packaged as myBus.js:

import mitt from 'mitt'
export default mitt()

Alternatively, it can also be defined as a global variable:

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

Then encapsulate a 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
}

Of course, for the convenience of management, you can also introduce mitt separately where you need it.
Example: Let's say we have a sidebar and header that contains a button to close/open the sidebar, and we need that button to toggle the sidebar expanded or closed.

//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>

Guess you like

Origin blog.csdn.net/weixin_49609457/article/details/125679873