Vue 组件之间传值

  • Vue 组件之间传值已关闭评论
  • 97 次浏览
  • A+
所属分类:Web前端
摘要

一、Vue 组件之间传值的主要方法 Vue 3 对于组件之间传递值的基本思想与 Vue 2 相似,但是有一些语法和 API 上的改变,主要的传值方法有以下几种:

一、Vue 组件之间传值的主要方法

Vue 3 对于组件之间传递值的基本思想与 Vue 2 相似,但是有一些语法和 API 上的改变,主要的传值方法有以下几种:

1、父组件向子组件传值,使用 props:可以通过在子组件上绑定 props,然后在父组件中通过 v-bind 绑定相应的数据来传递数据。

2、子组件向父组件传值,使用 $emit:可以通过在子组件中使用 $emit 触发自定义事件,并在父组件中使用 v-on 监听相应的事件来传递数据。

3、兄弟组件之间传值:可以通过使用一个共同的父组件,然后将需要共享的数据放在父组件的 data 中,再通过 props 将数据传递给各自的子组件。

4、跨级组件传值,使用 provide 和 inject(同样适用于父子组件传值):provide 可以在祖先组件中定义一个值或者方法,然后在子孙组件中使用 inject 来注入这个值或者方法。

5、使用全局事件总线:可以使用 Vue 的事件机制,通过在 Vue 实例上使用 $on 来监听事件,然后在其他组件中使用 $emit 触发相应的事件来传递数据。这种方式可以在任意组件之间传递数据。

6、使用 Vuex:当应用的数据状态比较复杂或者需要在多个组件之间共享时,可以使用 Vuex,它是一个专为 Vue.js 应用程序开发的状态管理模式。可以在任何组件中访问和修改 Vuex 存储的数据,通过 mutations 来修改状态,通过 actions 来触发 mutations。这种方式可以方便地在不同的组件中进行状态管理和数据共享。

7、使用 $attrs 和 $listeners,$attrs 和 $listeners 是常用的两个特殊属性,它们可以用来向组件传递属性和事件监听器。

8、使用 $refs:可以使用 Vue 提供的 $refs 属性来获取组件实例,然后通过调用组件的方法来进行数据传递。这种方式不推荐使用,因为不易维护和调试。

9、使用事件总线库:可以使用 Vue.js 的第三方库如 Event Bus、Tiny-Emmiter 等来传递数据。这些库提供了一种方便、简单的方式来在不同的组件之间进行事件传递。但是需要注意,使用第三方库可能会增加项目的复杂性和维护成本。

二、Vue 2 组件之间传值示例代码

  • 1、父组件向子组件传值,使用 props:可以通过在子组件上绑定 props,然后在父组件中通过 v-bind 绑定相应的数据来传递数据。

父组件中的代码:

<template>   <div>     <child-component :prop-a="dataA"></child-component>   </div> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: {     ChildComponent,   },   data() {     return {       dataA: 'data from parent',     };   }, }; </script>

子组件中的代码:

<template>   <div>     {{ propA }}   </div> </template>  <script> export default {   props: {     propA: String,   }, }; </script>
  • 2、子组件向父组件传值,使用 $emit:可以通过在子组件中使用 $emit 触发自定义事件,并在父组件中使用 v-on 监听相应的事件来传递数据。

子组件中的代码:

<template>   <div>     <button @click="sendDataToParent">Send Data To Parent</button>   </div> </template>  <script> export default {   data() {     return {       dataB: 'data from child',     };   },   methods: {     sendDataToParent() {       this.$emit('send-data', this.dataB);     },   }, }; </script>

父组件中的代码:

<template>   <div>     <child-component @send-data="receiveDataFromChild"></child-component>   </div> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: {     ChildComponent,   },   methods: {     receiveDataFromChild(dataB) {       console.log(dataB);     },   }, }; </script>
  • 3、兄弟组件之间传值:可以通过使用一个共同的父组件,然后将需要共享的数据放在父组件的 data 中,再通过 props 将数据传递给各自的子组件。

父组件中的代码:

<template>   <div>     <child-a :prop-a="dataA"></child-a>     <child-b :prop-b="dataB"></child-b>   </div> </template>  <script> import ChildA from './ChildA.vue'; import ChildB from './ChildB.vue';  export default {   components: {     ChildA,     ChildB,   },   data() {     return {       dataA: 'data from parent to child a',       dataB: 'data from parent to child b',     };   }, }; </script>

子组件 A 中的代码:

<template>   <div>     {{ propA }}   </div> </template>  <script> export default {   props: {     propA: String,   }, }; </script>

子组件 B 中的代码:

<template>   <div>     {{ propB }}   </div> </template>  <script> export default {   props: {     propB: String,   }, }; </script>
  • 4、跨级组件传值,使用 provide 和 inject(该方法也可用于父子组件传值):provide 可以在祖先组件中定义一个值或者方法,然后在子孙组件中使用 inject 来注入这个值或者方法。

祖先组件中的代码:

<template>   <div>     <child-a></child-a>   </div> </template>  <script> import ChildA from './ChildA.vue';  export default {   components: {     ChildA,   },   provide() {     return {       sharedData: 'data from ancestor',     };   }, }; </script>

子孙组件 A 中的代码:

<template>   <div>     {{ sharedData }}   </div> </template>  <script> export default {   inject: ['sharedData'], }; </script>
  • 5、使用全局事件总线:可以使用 Vue 的事件机制,通过在 Vue 实例上使用 $on 来监听事件,然后在其他组件中使用 $emit 触发相应的事件来传递数据。这种方式可以在任意组件之间传递数据。

在 main.js 中定义一个空的 Vue 实例作为事件总线:

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

子组件 A 中的代码:

<template>   <div>     <button @click="sendDataToSibling">Send Data To Sibling</button>   </div> </template>  <script> import { bus } from './main';  export default {   methods: {     sendDataToSibling() {       bus.$emit('send-data', 'data from child a');     },   }, }; </script>

子组件 B 中的代码:

<template>   <div>     {{ dataFromSibling }}   </div> </template>  <script> import { bus } from './main';  export default {   data() {     return {       dataFromSibling: '',     };   },   mounted() {     bus.$on('send-data', (data) => {       this.dataFromSibling = data;     });   }, }; </script>
  • 6、使用 Vuex:当应用的数据状态比较复杂或者需要在多个组件之间共享时,可以使用 Vuex,它是一个专为 Vue.js 应用程序开发的状态管理模式。可以在任何组件中访问和修改 Vuex 存储的数据,通过 mutations 来修改状态,通过 actions 来触发 mutations。这种方式可以方便地在不同的组件中进行状态管理和数据共享。

在 store.js 中定义一个 Vuex store:

import Vue from 'vue'; import Vuex from 'vuex';  Vue.use(Vuex);  const store = new Vuex.Store({   state: {     dataC: 'data from Vuex',   },   mutations: {     updateDataC(state, payload) {       state.dataC = payload;     },   }, });  export default store;

子组件 A 中的代码:

<template>   <div>     <button @click="sendDataToSibling">Send Data To Sibling</button>   </div> </template>  <script> import { mapMutations } from 'vuex';  export default {   methods: {     ...mapMutations(['updateDataC']),     sendDataToSibling() {       this.updateDataC('data from child a');     },   }, }; </script>

子组件 B 中的代码:

<template>   <div>     {{ dataC }}   </div> </template>  <script> import { mapState } from 'vuex';  export default {   computed: {     ...mapState(['dataC']),   }, }; </script>
  • 7、父子组件传值,使用 $attrs$listeners

$attrs 是一个包含了父组件传递给子组件的所有属性的对象,可以在子组件中通过访问 $attrs 来获取这些属性。如果不希望某些属性传递到子组件中,可以在子组件中使用 v-bind="$attrs" 并指定排除的属性名称,或者在父组件中使用 .sync 修饰符,将属性绑定到子组件的一个名为 $attrs 的属性上。

$listeners 是一个包含了父组件传递给子组件的所有事件监听器的对象,可以在子组件中通过访问 $listeners 来获取这些事件监听器。如果需要在子组件中监听某个事件,可以使用 v-on="$listeners" 将所有的事件监听器绑定到子组件上。

$attrs 和 $listeners 是常用的两个特殊属性,它们可以用来向组件传递属性和事件监听器。假设我们有一个父组件和一个子组件,子组件需要接收父组件的一些属性和事件监听器,同时还需要把这些属性和事件传递给子组件的某个子元素。

父组件中的代码:

<template>   <div>     <child-component :title="title" v-on:click="handleClick" />   </div> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: { ChildComponent },   data() {     return {       title: 'Hello World',     };   },   methods: {     handleClick() {       console.log('Button Clicked');     },   }, }; </script>

子组件中的代码:

<template>   <div>     <button @click="$emit('click')">Click me</button>     <div v-bind="$attrs">       <slot />     </div>   </div> </template>  <script> export default {   inheritAttrs: false,   props: {     title: {       type: String,       default: '',     },   },   mounted() {     console.log(this.$attrs);     console.log(this.$listeners);   }, }; </script>

在子组件中,我们使用 v-bind="$attrs" 把所有父组件传递过来的属性绑定到子元素上。同时,我们使用 $emit('click') 来触发父组件传递过来的点击事件。

在子组件 中,需要设置 inheritAttrs: false,来禁止自动将父组件传递的属性绑定到子组件的根元素上。这样,我们就可以使用 v-bind="$attrs" 把所有属性绑定到子元素上。

在 mounted 钩子中,我们可以通过 this.$attrsthis.$listeners 来分别访问所有属性和事件监听器。这样,我们就可以在子组件中使用这些属性和事件了。

  • 8、使用 $refs:可以使用 Vue 提供的 $refs 属性来获取组件实例,然后通过调用组件的方法来进行数据传递。这种方式不推荐使用,因为不易维护和调试。
  • 9、使用事件总线库:可以使用 Vue.js 的第三方库如 Event Bus、Tiny-Emmiter 等来传递数据。这些库提供了一种方便、简单的方式来在不同的组件之间进行事件传递。但是需要注意,使用第三方库可能会增加项目的复杂性和维护成本。

三、Vue 3 组件之间传值示例代码

  • 1、Props

Props 是一种在组件之间传递数据的方式,通过在组件标签上使用属性绑定,父组件可以向子组件传递数据。在子组件中,通过在 props 中定义对应的属性名,可以获取到父组件传递过来的数据。

例如,父组件中的模板:

<template>   <child-component :message="hello"></child-component> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: {     ChildComponent   },   data() {     return {       hello: 'Hello from parent!'     };   } }; </script>

子组件中的模板:

<template>   <div>{{ message }}</div> </template>  <script> export default {   props: {     message: String   } }; </script>
  • 2、$emit 

$emit  是一种在子组件中触发事件的方式,通过在子组件中使用 $emit 方法,可以向父组件发送数据。在父组件中,通过在子组件标签上使用 v-on@ 语法,可以监听子组件触发的事件,并获取子组件发送的数据。

例如,子组件中的模板:

<template>   <button @click="sendMessage">Send Message</button> </template>  <script> export default {   methods: {     sendMessage() {       this.$emit('message-sent', 'Hello from child!');     }   } }; </script>

父组件中的模板:

<template>   <child-component @message-sent="receiveMessage"></child-component> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: {     ChildComponent   },   methods: {     receiveMessage(message) {       console.log(message);     }   } }; </script>
  • 3、Provide/Inject

Provide/Inject 是一种在祖先组件和后代组件之间共享数据的方式。通过在祖先组件中使用 provide 方法提供数据,在后代组件中使用 inject 方法获取数据。

例如,祖先组件中的模板:

<template>   <child-component></child-component> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: {     ChildComponent   },   provide() {     return {       message: 'Hello from ancestor!'     };   } }; </script>

后代组件中的模板:

<template>   <div>{{ message }}</div> </template>  <script> export default {   inject: ['message'] }; </script>
  • 4、$attrs 和 $listeners

$attrs 和 $listeners 是在 Vue 2 中引入的特性,但在 Vue 3 中也得到了支持。

例如,父组件中的模板:

<template>   <child-component message="Hello from parent!" @click="handleClick"></child-component> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: {     ChildComponent   },   methods: {     handleClick() {       console.log('Clicked!');     }   } }; </script>

子组件中的模板:

<template>   <div v-bind="$attrs" v-on="$listeners">{{ message }}</div> </template>  <script> export default {   props: {     message: String   } }; </script>
  • 5、provide/inject 与 props 的结合使用

在 Vue 3 中,provide 和 inject 可以与 props 结合使用,从而实现一种高级的数据传递方式。具体做法是,在祖先组件中使用 provide 方法提供数据,并在后代组件中使用 inject 方法获取数据;同时,在后代组件中,可以在 props 中声明和接收数据,从而实现数据的类型检查和默认值设定。

例如,祖先组件中的模板:

<template>   <child-component></child-component> </template>  <script> import ChildComponent from './ChildComponent.vue';  export default {   components: {     ChildComponent   },   provide() {     return {       message: 'Hello from ancestor!'     };   } }; </script>

后代组件中的模板:

<template>   <div>{{ message }}</div> </template>  <script> export default {   inject: ['message'],   props: {     message: {       type: String,       default: 'Hello from default!'     }   } }; </script>

在上面的例子中,子组件会首先从祖先组件中获取名为 message 的数据,如果没有提供,则使用默认值 Hello from default!。在子组件中,props 会覆盖 provide/inject,因此如果父组件和子组件都提供了同一个属性,子组件中的 props 值会覆盖 provide/inject 中的值。

  • 6、Vuex

Vuex 是一种专门用于管理应用程序状态的库,可以用于跨组件传递数据。在 Vuex 中,可以定义一个全局的状态管理器,所有的组件都可以通过 getter 和 setter 方法访问和修改这个状态管理器中的数据。

例如,定义一个 Vuex store:

import { createStore } from 'vuex';  const store = createStore({   state: {     message: 'Hello from store!'   },   mutations: {     updateMessage(state, message) {       state.message = message;     }   },   getters: {     getMessage(state) {       return state.message;     }   } });  export default store;

在组件中使用 Vuex:

<template>   <div>{{ message }}</div>   <button @click="updateMessage">Update message</button> </template>  <script> import { mapGetters, mapMutations } from 'vuex';  export default {   computed: {     ...mapGetters(['getMessage'])   },   methods: {     ...mapMutations(['updateMessage'])   } }; </script>

在这个例子中,组件通过 mapGetters 方法将 Vuex store 中的 getMessage 方法映射为组件中的计算属性,从而获取 Vuex store 中的数据;同时,通过 mapMutations 方法将 Vuex store 中的 updateMessage 方法映射为组件中的方法,从而修改 Vuex store 中的数据。

  • 7、EventBus

EventBus 是一种自定义事件总线,可以用于在任意组件之间传递数据。在 EventBus 中,可以定义一个全局的事件中心,所有的组件都可以通过 $on 和 $emit 方法监听和触发自定义事件。

例如,定义一个 EventBus:

import mitt from 'mitt';  const bus = mitt();  export default bus;

在组件中使用 EventBus:

<template>   <div>{{ message }}</div>   <button @click="updateMessage">Update message</button> </template>  <script> import bus from './event-bus';  export default {   data() {     return {       message: 'Hello from component!'     };   },   methods: {     updateMessage() {       this.message = 'New message!';       bus.emit('message-updated', this.message);     }   },   created() {     bus.on('message-updated', message => {       console.log(message);     });   } }; </script>

在这个例子中,组件中的 updateMessage 方法通过 EventBus 的 emit 方法触发了一个名为 message-updated 的自定义事件,并将修改后的消息作为参数传递给事件处理函数;同时,在组件的 created 生命周期钩子中,通过 EventBus 的 on 方法监听名为 message-updated 的自定义事件,并在事件处理函数中打印接收到的消息。

 

总之,Vue 3 中组件之间传值的方式很多,可以根据具体的场景选择最适合的方式。使用 props 和 $emit 可以实现父子组件之间的传值,使用 provide 和 inject 可以实现祖先组件向后代组件的传值,使用 Vuex 和 EventBus 可以实现任意组件之间的传值。在选择组件传值方式时,还应该考虑数据的安全性、可维护性和性能等因素。

四、Vue 2 和 Vue 3 组件之间传值的区别

Vue 2 和 Vue 3 之间在组件之间传递值的方法有一些不同之处。下面是一些主要的区别:

  1. Props

在 Vue 2 中,父组件通过 props 把数据传递给子组件。子组件可以在 props 选项中声明它们需要的 props,然后在组件的模板中使用它们。

在 Vue 3 中,props 的使用与 Vue 2 类似,但有一些重要的变化。首先,props 的声明方式已经发生了变化,现在使用 ES6 的解构语法来声明。其次,Vue 3 强制 props 的类型检查,并提供了更多的选项来控制 props 的行为,例如默认值和必需性等。

  1. Emit

在 Vue 2 中,子组件通过 emit 向父组件发送消息。子组件可以使用 this.$emit 方法触发一个自定义事件,并可以传递任意数据作为事件的参数。父组件可以监听子组件触发的事件,并在事件处理程序中处理传递的数据。

在 Vue 3 中,emit 的使用与 Vue 2 相似,但也有一些重要的变化。首先,Vue 3 引入了新的 setup() API,该 API 取代了 Vue 2 中的 created 和 mounted 等生命周期钩子函数。其次,emit 的使用方式已经改变,现在使用 v-model 代替 this.$emit。v-model 是一个语法糖,允许在父子组件之间双向绑定数据。

  1. Provide/Inject

在 Vue 2 中,父组件可以通过 provide 方法向子组件传递数据,子组件可以使用 inject 方法获取数据。provide 和 inject 允许在组件树中的任何地方传递数据,而不需要通过 props 一级一级地传递。

在 Vue 3 中,provide 和 inject 的使用方式与 Vue 2 相同。但是,Vue 3 提供了新的 reactive 和 readonly 方法,允许在 provide 中提供响应式的数据。这意味着,如果在 provide 中提供的数据发生变化,子组件中使用这些数据的地方也会相应地更新。

 

Vue 3 对于组件之间传递值的基本思想与 Vue 2 相似,但是有一些语法和 API 上的改变。这些变化旨在提供更好的类型检查、更好的性能和更好的开发体验。