- 通过 props 传递
- 通过
$emit触发自定义事件 - 使用 ref
- EventBus
- $parent 或 $root
- attrs 与 listeners
- Provide 与 Inject
- Vuex、Pinia
https://cn.vuejs.org/api/component-instance.html
父传子
父组件
<template>
<div>
<h1>向子组件传递a的值</h1>
<son :A="a"/>
</div>
</template>子组件
<template>
<div>
a的值是:{{ value }}
</div>
</template>
<script setup lang="ts">
import {ref} from "vue";
const props = defineProps<{
A: number
}>()
const value = ref<number>(props.A)
</script>每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告: ❌ 警告!prop 是只读的!
如果你想要改 可以套一层
1.在父组件中定义函数,该函数用于接收子组件通过emits传过来的值以及修改父组件页面中的值
2.在父组件标签内部把该函数传递给子组件
3.子组件通过emits方式接收
4.子组件通过某种方式触发该emits
父组件
<template>
<div>
<div>a:{{a}}</div>
<son @changeA="triggerEvent"/>
</div>
</template>
<script setup lang="ts">
import{ref} from "vue";
import Son from "@/components/son.vue";
const a=ref(0);
//这里的X是子组件通过emit传递过来的
const triggerEvent=(X:number)=>{
a.value=X
}
</script>子组件
<template>
<div>
<button @click="emits('changeA',20)">修改父组件A的值</button>
</div>
</template>
<script setup lang="ts">
const emits=defineEmits<{
(e:'changeA',value:number):void
}>()
</script>
- 父组件在使用子组件的时候设置
ref - 父组件通过设置子组件
ref来获取数据
父组件
<Children ref="foo" />
this.$refs.foo // 获取子组件实例,通过子组件实例我们就能拿到对应的数据 非响应式- 在祖先组件定义
provide属性,返回传递的值 - 在后代组件通过
inject接收组件传递过来的值
父组件
<template>
<div>
<h1>父组件</h1>
父组件的a值:{{a}}
<button @click="add">a值+1</button>
<hr>
<son/>
</div>
</template>
<script setup lang="ts">
import{ref,provide} from "vue";
import Son from "@/components/son.vue";
const a=ref<number>(0);
provide('A',a);
const add=()=>{
a.value++;
}
</script>
子组件
<template>
<div>
<h1>孙组件</h1>
孙组件的a值:{{ a }}
<button @click="add">a值+1</button>
</div>
</template>
<script setup lang="ts">
import {inject, Ref} from "vue";
const a = inject<Ref<number>>('A')
const add = () => {
if (a) {
a.value++
}
}
</script>pinia 安装会在router后
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')定义store 内有三个部分
ref()就是state属性computed()就是gettersfunction()就是actionsaction可以是异步的,你可以在它们里面await调用任何 API
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})使用store
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// `name` 和 `doubleCount` 是响应式的 ref
// 同时通过插件添加的属性也会被提取为 ref
// 并且会跳过所有的 action 或非响应式 (不是 ref 或 reactive) 的属性
const { name, doubleCount } = storeToRefs(store)
// 作为 action 的 increment 可以直接解构
const { increment } = store
</script>v3干掉了EventBus vue3-eventbus mitt
- 使用场景:兄弟组件传值
- 创建一个中央事件总线
EventBus - 兄弟组件通过
$emit触发自定义事件,$emit第二个参数为传递的数值 - 另一个兄弟组件通过
$on监听自定义事件
- 通过共同祖辈
$parent或者$root搭建通信桥连
兄弟组件
this.$parent.on('add',this.add)
另一个兄弟组件
this.$parent.emit('add')
也被v3砍了应该
v3 listeners砍了
- 适用场景:祖先传递数据给子孙
- 设置批量向下传属性
$attrs和$listeners - 包含了父级作用域中不作为
prop被识别 (且获取) 的特性绑定 ( class 和 style 除外)。 - 可以通过
v-bind="$attrs"传⼊内部组件
// child:并未在props中声明foo
<p>{{$attrs.foo}}</p>
// parent
<HelloWorld foo="foo"/> // 给Grandson隔代传值,communication/index.vue
<Child2 msg="lalala" @some-event="onSomeEvent"></Child2>
// Child2做展开
<Grandson v-bind="$attrs" v-on="$listeners"></Grandson>
// Grandson使⽤
<div @click="$emit('some-event', 'msg from grandson')">
{{msg}}
</div> 