【前端】【面试】【经典一道题】vue中组件传值的几种方式

父子组件传值

1. 父传子:props

这是最常见的父组件向子组件传递数据的方式。父组件在使用子组件时,通过在子组件标签上绑定属性来传递数据,子组件通过 props 选项接收这些数据。

<!-- 父组件 -->
<template>
  <div>
    <ChildComponent :parentMsg="message" />
  </div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const message = ref('来自父组件的消息');
</script>

<!-- 子组件 ChildComponent.vue -->
<template>
  <div>
    <p>{{ parentMsg }}</p>
  </div>
</template>

<script setup>
const props = defineProps({
  parentMsg: {
    type: String,
    required: true
  }
});
</script>
2. 子传父:$emit(自定义事件)

子组件可以通过 $emit 触发自定义事件,并将数据作为参数传递给父组件,父组件监听这些自定义事件来接收数据。

<!-- 子组件 ChildComponent.vue -->
<template>
  <div>
    <button @click="sendDataToParent">发送数据给父组件</button>
  </div>
</template>

<script setup>
import { defineEmits } from 'vue';

const emit = defineEmits(['childEvent']);

const sendDataToParent = () => {
  const data = '来自子组件的数据';
  emit('childEvent', data);
};
</script>

<!-- 父组件 -->
<template>
  <div>
    <ChildComponent @childEvent="handleChildEvent" />
    <p>{{ receivedData }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const receivedData = ref('');

const handleChildEvent = (data) => {
  receivedData.value = data;
};
</script>
3. 父子双向绑定:v-model

v-model 是一种语法糖,结合了 props$emit,可以实现父组件和子组件之间的双向数据绑定。

<!-- 子组件 ChildComponent.vue -->
<template>
  <div>
    <input v-model="modelValue" @input="updateValue">
  </div>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';

const props = defineProps({
  modelValue: String
});

const emit = defineEmits(['update:modelValue']);

const updateValue = (event) => {
  emit('update:modelValue', event.target.value);
};
</script>

<!-- 父组件 -->
<template>
  <div>
    <ChildComponent v-model="parentValue" />
    <p>{{ parentValue }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const parentValue = ref('初始值');
</script>

兄弟组件传值

1. 事件总线(适用于小型项目)

事件总线是一个全局的事件发射器,兄弟组件可以通过它来发布和订阅事件,从而实现数据传递。在 Vue 3 中,可使用 mitt 库来实现事件总线。

// eventBus.js
import mitt from 'mitt';
const eventBus = mitt();
export default eventBus;
<!-- 发送数据的兄弟组件 -->
<template>
  <div>
    <button @click="sendData">发送数据</button>
  </div>
</template>

<script setup>
import eventBus from './eventBus.js';

const sendData = () => {
  const data = '来自兄弟组件的数据';
  eventBus.emit('brotherEvent', data);
};
</script>

<!-- 接收数据的兄弟组件 -->
<template>
  <div>
    <p>{{ receivedData }}</p>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import eventBus from './eventBus.js';

const receivedData = ref('');

const handleEvent = (data) => {
  receivedData.value = data;
};

onMounted(() => {
  eventBus.on('brotherEvent', handleEvent);
});

onUnmounted(() => {
  eventBus.off('brotherEvent', handleEvent);
});
</script>
2. 状态管理库(适用于大型项目)

使用状态管理库(如 Vuex 或 Pinia),可以将共享数据存储在一个集中的位置,兄弟组件可以从中获取和修改数据。

// stores/counter.js (Pinia 示例)
import { defineStore } from 'pinia';

export const useSharedStore = defineStore('shared', {
  state: () => ({
    sharedData: '初始共享数据'
  }),
  actions: {
    updateSharedData(newData) {
      this.sharedData = newData;
    }
  }
});
<!-- 发送数据的兄弟组件 -->
<template>
  <div>
    <button @click="updateData">更新共享数据</button>
  </div>
</template>

<script setup>
import { useSharedStore } from '../stores/counter';

const sharedStore = useSharedStore();

const updateData = () => {
  sharedStore.updateSharedData('新的共享数据');
};
</script>

<!-- 接收数据的兄弟组件 -->
<template>
  <div>
    <p>{{ sharedStore.sharedData }}</p>
  </div>
</template>

<script setup>
import { useSharedStore } from '../stores/counter';

const sharedStore = useSharedStore();
</script>
3. localStorage

localStorage 是浏览器提供的一种本地存储机制,可以在不同组件之间共享数据。一个组件将数据存储到 localStorage 中,另一个组件可以从 localStorage 中读取数据。

<!-- 发送数据的兄弟组件 -->
<template>
  <div>
    <button @click="saveDataToLocalStorage">保存数据到 localStorage</button>
  </div>
</template>

<script setup>
const saveDataToLocalStorage = () => {
  const data = '通过 localStorage 传递的数据';
  localStorage.setItem('sharedData', data);
};
</script>

<!-- 接收数据的兄弟组件 -->
<template>
  <div>
    <p>{{ receivedData }}</p>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';

const receivedData = ref('');

onMounted(() => {
  const data = localStorage.getItem('sharedData');
  if (data) {
    receivedData.value = data;
  }
});
</script>

跨层级组件传值

1. provide/inject

provideinject 用于实现跨层级的组件数据传递。祖先组件通过 provide 提供数据,后代组件通过 inject 注入这些数据。

<!-- 祖先组件 -->
<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script setup>
import { provide, ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const sharedData = ref('来自祖先组件的共享数据');
provide('sharedData', sharedData);
</script>

<!-- 后代组件(可以是多层嵌套) -->
<template>
  <div>
    <p>{{ injectedData }}</p>
  </div>
</template>

<script setup>
import { inject } from 'vue';

const injectedData = inject('sharedData');
</script>
2. 状态管理库

和兄弟组件传值类似,使用状态管理库(如 Vuex 或 Pinia)可以方便地实现跨层级组件之间的数据共享和传递。所有组件都可以访问和修改存储在状态管理库中的数据。

3. 路由传值

在 Vue Router 中,可以通过路由参数或查询参数来传递数据。这种方式适用于在路由跳转时传递数据给目标组件。

路由参数
// 路由配置
import { createRouter, createWebHistory } from 'vue-router';
import ComponentA from './ComponentA.vue';
import ComponentB from './ComponentB.vue';

const routes = [
  {
    path: '/componentB/:id',
    name: 'ComponentB',
    component: ComponentB
  },
  {
    path: '/componentA',
    name: 'ComponentA',
    component: ComponentA
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;
<!-- 发送数据的组件 ComponentA.vue -->
<template>
  <div>
    <router-link :to="{ name: 'ComponentB', params: { id: 123 } }">跳转到 ComponentB 并传参</router-link>
  </div>
</template>

<script setup></script>

<!-- 接收数据的组件 ComponentB.vue -->
<template>
  <div>
    <p>接收到的参数 id: {{ $route.params.id }}</p>
  </div>
</template>

<script setup>
import { useRoute } from 'vue-router';

const route = useRoute();
</script>
查询参数
<!-- 发送数据的组件 ComponentA.vue -->
<template>
  <div>
    <router-link :to="{ name: 'ComponentB', query: { message: 'Hello from ComponentA' } }">跳转到 ComponentB 并传参</router-link>
  </div>
</template>

<script setup></script>

<!-- 接收数据的组件 ComponentB.vue -->
<template>
  <div>
    <p>接收到的查询参数 message: {{ $route.query.message }}</p>
  </div>
</template>

<script setup>
import { useRoute } from 'vue-router';

const route = useRoute();
</script>

你可能感兴趣的:(面试考题专栏(前后端),vue.js,前端,javascript)