组件十大传值

一、definePropsdefineEmits

defineProps 用于定义子组件接收的 props,即父组件传递给子组件的数据。

  1. 接收父组件传递的数据:定义子组件可以接受的属性及其类型。
  2. 类型检查:确保传递的数据符合预期的类型。

defineEmits 用于定义子组件可以触发的事件,从而向父组件传递数据或通知父组件发生了某些操作。

  1. 触发事件:子组件可以通过触发事件来通知父组件。
  2. 传递数据 :事件可以携带数据传递给父组件。
javascript 复制代码
//父组件:
<template>
  <ChildComponent :message="parentMessage" @childEvent="handleChildEvent" />
</template>

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

const parentMessage = ref('Hello from Parent');

const handleChildEvent = (message) => {
  console.log('Received from child:', message);
};
</script>
javascript 复制代码
//子组件
<template>
  <div>
    {{ message }}
    <button @click="sendMessageToParent">Send Message to Parent</button>
  </div>
</template>

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

const props = defineProps({
  message: String,
  default:''
});

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

const sendMessageToParent = () => {
  emit('childEvent', 'Hello from Child');
};
</script>

二、v-model

双向数据绑定

javascript 复制代码
// 父组件
<template>
  <ChildComponent v-model="parentMessage" />
</template>

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

const parentMessage = ref('Hello from Parent');
</script>
javascript 复制代码
// 子组件
<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</template>

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

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

const emit = defineEmits(['update:modelValue']);
</script>

自定义 v-model 的 prop 和 event 名称

javascript 复制代码
// 父组件
<template>
  <ChildComponent v-model:title="parentTitle" />
</template>

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

const parentTitle = ref('Hello from Parent');
</script>
javascript 复制代码
// 子组件
<template>
  <input :value="title" @input="$emit('update:title', $event.target.value)" />
</template>

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

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

const emit = defineEmits(['update:title']);
</script>

三、refs

直接访问子组件实例或 DOM 元素,即操作dom节点。

javascript 复制代码
// 父组件
<template>
  <ChildComponent ref="childRef" />
  <button @click="callChildMethod">Call Child Method</button>
</template>

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

const childRef = ref(null);

const callChildMethod = () => {
  childRef.value.childMethod();
};
</script>
javascript 复制代码
// 子组件
<template>
  <div>Child Component</div>
</template>

<script setup>
const childMethod = () => {
  console.log('Child method called');
};

defineExpose({
  childMethod
});
</script>

四、provideinject

祖先组件向后代组件传递数据,适用于多层级组件之间共享数据传值,从而 减少 props 钓鱼(prop drilling)的问题**。**

javascript 复制代码
<template>
  <div>
    <h1>Ancestor Component</h1>
    <button @click="changeTheme">Change Theme</button>
    <ChildComponent />
  </div>
</template>

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

const themeColor = ref<string>('blue');

// 提供主题颜色
provide('themeColor', themeColor);

const changeTheme = () => {
  themeColor.value = themeColor.value === 'blue' ? 'green' : 'blue';
};
</script>
javascript 复制代码
//中间组件-子组件
<template>
  <div>
    <h2>Child Component</h2>
    <GrandchildComponent />
  </div>
</template>

<script setup>
import GrandchildComponent from './GrandchildComponent.vue';
</script>
javascript 复制代码
<template>
  <div :style="{ color: themeColor }">
    <h3>Grandchild Component</h3>
    <p>This text is colored by the theme color provided by the ancestor component.</p>
  </div>
</template>

<script setup lang="ts">
import { inject } from 'vue';

// 定义类型
type ThemeColor = string;

// 注入主题颜色,提供默认值 'red'
const themeColor = inject<ThemeColor>('themeColor', 'red');
</script>

五、 路由传参

Query

通过 URL 查询参数传递数据

javascript 复制代码
// 父组件
<template>
  <router-link :to="{ name: 'Child', query: { message: 'Hello from Parent' } }">Go to Child</router-link>
</template>
javascript 复制代码
// 子组件
<template>
  <div>{{ message }}</div>
</template>

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

const route = useRoute();
const message = route.query.message;
</script>

Params

通过 URL 参数传递数据

javascript 复制代码
// 父组件
<template>
  <router-link :to="{ name: 'Child', params: { id: 123 } }">Go to Child</router-link>
</template>
javascript 复制代码
//子组件
<template>
  <div>ID: {{ id }}</div>
</template>

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

const route = useRoute();
const id = route.params.id;
</script>

State

通过路由状态传递数据

javascript 复制代码
//父组件
<template>
  <router-link :to="{ name: 'Child', state: { message: 'Hello from Parent' } }">Go to Child</router-link>
</template>
javascript 复制代码
// 子组件
<template>
  <div>{{ message }}</div>
</template>

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

const route = useRoute();
const message = route.state?.message || '';
</script>

六、Pinia

vue3状态管理

javascript 复制代码
// Pinia Store
import { defineStore } from 'pinia';

export const useMainStore = defineStore('main', {
  state: () => ({
    message: 'Hello from Pinia'
  }),
  actions: {
    updateMessage(newMessage) {
      this.message = newMessage;
    }
  }
});
javascript 复制代码
// 父组件
<template>
  <div>{{ message }}</div>
  <button @click="updateMessage">Update Message</button>
</template>

<script setup>
import { useMainStore } from '../stores/main';

const store = useMainStore();

const message = store.message;

const updateMessage = () => {
  store.updateMessage('Updated Message');
};
</script>

七、 浏览器缓存**localStoragesessionStorage**

javascript 复制代码
// 父组件
<template>
  <div>{{ cachedMessage }}</div>
  <input v-model="cachedMessage" @input="saveMessage" />
</template>

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

const cachedMessage = ref(localStorage.getItem('message') || '');

const saveMessage = () => {
  localStorage.setItem('message', cachedMessage.value);
};

onMounted(() => {
  cachedMessage.value = localStorage.getItem('message') || '';
});
</script>

八、 window 对象全局挂载

javascript 复制代码
// 父组件
<template>
  <div>{{ globalMessage }}</div>
  <input v-model="globalMessage" @input="updateGlobalMessage" />
</template>

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

const globalMessage = ref(window.globalMessage || '');

const updateGlobalMessage = () => {
  window.globalMessage = globalMessage.value;
};

onMounted(() => {
  globalMessage.value = window.globalMessage || '';
});
</script>

九、兄弟组件传值 (mitt)

javascript 复制代码
// 安装 mitt
npm install mitt
javascript 复制代码
// 创建事件总线
// eventBus.js
import mitt from 'mitt';

export const emitter = mitt();
javascript 复制代码
// 兄弟A
<template>
  <button @click="sendMessageToSibling">Send Message to Sibling</button>
</template>

<script setup>
import { emitter } from '../eventBus';

const sendMessageToSibling = () => {
  emitter.emit('siblingEvent', 'Hello from Sibling A');
};
</script>
javascript 复制代码
// 兄弟B
<template>
  <div>{{ message }}</div>
</template>

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

const message = ref('');

const handleMessage = (msg) => {
  message.value = msg;
};

onMounted(() => {
  emitter.on('siblingEvent', handleMessage);
});

onUnmounted(() => {
  emitter.off('siblingEvent', handleMessage);
});
</script>

十、$attrs

  1. 透传属性: 将父组件传递的所有非 prop 属性自动应用到子组件的根元素或其他指定元素上。
  2. 样式和类 : 传递 classstyle 属性,以便子组件能够继承父组件的样式。
  3. 事件监听器: 传递事件监听器,使得子组件能够响应父组件传递的事件。
javascript 复制代码
// 父组件
<template>
  <ChildComponent class="parent-class" style="color: red;" custom-attr="custom-value" @click="handleClick" />
</template>

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

const handleClick = () => {
  console.log('Clicked on ChildComponent');
};
</script>
javascript 复制代码
// 子组件
<template>
  <div v-bind="$attrs">
    Child Component
  </div>
</template>

<script setup>
// 子组件不需要显式声明父组件传递的属性
</script>

<style scoped>
.parent-class {
  background-color: yellow;
}
</style>

默认情况下,Vue 会将 $attrs 应用到子组件的根元素上。如果你不希望这样做,可以通过设置 inheritAttrs: false 来禁用这个行为。

javascript 复制代码
// 子组件
<template>
  <div>
    <span v-bind="$attrs">Child Component</span>
  </div>
</template>

<script setup>
// 禁用自动应用 $attrs 到根元素
defineOptions({
  inheritAttrs: false
});
</script>

如果想访问$attrs对象

javascript 复制代码
// 子组件
<template>
  <div>
    <span v-bind="filteredAttrs">Child Component</span>
  </div>
</template>

<script setup>
import { useAttrs, computed } from 'vue';

const attrs = useAttrs();

const filteredAttrs = computed(() => {
  // 过滤掉不需要的属性
  return Object.fromEntries(
    Object.entries(attrs).filter(([key]) => !['custom-attr'].includes(key))
  );
});
</script>
相关推荐
冰红茶-Tea17 分钟前
typescript数据类型(二)
前端·typescript
slongzhang_21 分钟前
elementPlus消息组件多按钮案例
前端·javascript·vue.js
会发光的猪。1 小时前
vue中el-select选择框带搜索和输入,根据用户输入的值显示下拉列表
前端·javascript·vue.js·elementui
旺旺大力包1 小时前
【 Git 】git 的安装和使用
前端·笔记·git
PP东1 小时前
ES学习class类用法(十一)
javascript·学习
海威的技术博客1 小时前
JS中的原型与原型链
开发语言·javascript·原型模式
雪落满地香1 小时前
前端:改变鼠标点击物体的颜色
前端
余生H2 小时前
前端Python应用指南(二)深入Flask:理解Flask的应用结构与模块化设计
前端·后端·python·flask·全栈
outstanding木槿2 小时前
JS中for循环里的ajax请求不数据
前端·javascript·react.js·ajax
酥饼~2 小时前
html固定头和第一列简单例子
前端·javascript·html