props
父组件传值给子组件
文档:props
emits
子组件调用父组件中的方法,并且可以传值给父组件
文档:emits
父组件:
<ChildComponent @loadData='fatherFun'/>
const fatherFun = (params:any) => {
console.log(params)
};
子组件:
//不需要引入 defineEmits
const emit = defineEmits(['loadData'])
const sonFun = () => {
emit('loadData', '我是来自子组件的参数哦~')
};
expose / ref
子组件通过
expose
暴露自身的方法和数据父组件通过
ref
获取子组件,调用其方法或访问数据文档:expose 、defineExpose
子组件:
//不需要引入 defineExpose
const childName = ref("这是子组件的属性");
defineExpose({
childName,
childMethod(){
console.log("这是子组件的方法")
}
});
父组件:
// 注意 ref="childRef"
<template>
<ChildComponent ref="childRef"></ChildComponent>
<button @click="handlerClick">按钮调用子组件方法</button>
</template>
<script setup lang="ts">
import ChildComponent from "./ChildComponent.vue"
import { ref } from "vue"
const childRef = ref<InstanceType<typeof ChildComponent>>()
const handlerClick=()=>{
// 获取子组件 childName 属性
console.log(childRef.value?.childName)
// 调用子组件 childMethod 方法
childRef.value?.childMethod()
}
</script>
attrs
在子组件中,没使用
prop
或emits
定义的attribute
,可以通过$attrs
来访问
父组件:
<child msg1="msg1" msg2="msg2" msg3="33" />
子组件:
<script setup lang="ts">
import { useAttrs } from "vue"
// 不需要引入 defineProps
const props = defineProps({
msg1: String
})
const attrs = useAttrs()
console.log(attrs)
// 结果:{ msg2:"22", msg3: "33" }
// 注释 defineProps 结果:{ msg1: "11", msg2:"22", msg3: "33" }
</script>
v-model
组件上的
v-model
使用modelValue
作为 prop 和update:modelValue
作为事件,可以支持多个数据双向绑定
单值 / 修饰符
-
组件上的
v-model
使用modelValue
作为 prop 和update:modelValue
作为事件 -
v-model
可通过.
的方式传入自定义的修饰符(内置的修饰符,例如
.trim
,.number
和.lazy
)
父组件:
<template>
<Child v-model="messageFromParent"/>
// <Child v-model.uppercase="messageFromParent"/>
</template>
const messageFromParent = ref('aaaa')
子组件:
<template>
<div>messageFromParent:{{modelValue}}</div>
<button @click="handleClick">点击修改</button>
</template>
<script setup lang="ts">
// v-model没有指定参数
// 接收父组件使用 v-model 传进来的值以及修饰符
const props = defineProps([
'modelValue',
'modelModifiers'
])
// 通知父组件修改值:update:modelValue
const emit = defineEmits(['update:modelValue'])
function handleClick() {
emit('update:modelValue', 'bbb')
if (props.modelModifiers?.uppercase) {
emit('update:modelValue', props.modelValue.toUpperCase())
}
}
</script>
如果没有其他逻辑,直接触发修改,可以优化成:
<template>
<div>messageFromParent:{{modelValue}}</div>
<button @click="$emit('update:modelValue', 'bbb')">点击修改父组件的 messageFromParent</button>
</template>
<script setup lang="ts">
defineProps([
'modelValue'
])
</script>
如果指定了参数,不用默认的modelValue
,相应修改:
<ChildComponent v-model:msg="messageFromParent" />
//子组件需要声明一个 `msg` prop
defineProps(['msg'])
//通过 `update:msg` 事件更新父组件值
defineEmits(['update:msg'])
多个 v-model 绑定
父组件:
<child v-model:msg1="msg1" v-model:msg2="value"></child>
<script setup>
import child from "./child.vue"
import { ref } from "vue"
const msg1 = ref("1111")
const msg2 = ref("2222")
</script>
子组件:
<template>
<div>msg1:{{msg1}}</div>
<div>msg2:{{msg2}}</div>
<button @click="handlerClick">修改父组件msg1、msg2的值</button>
</template>
<script setup>
// 接收
defineProps({
msg1: String,
msg2: String
})
// 不需要引入 defineEmits
const emit = defineEmits(['update:msg1', 'update:msg2'])
const handlerClick = () => {
emit("update:msg1", "新的msg1")
emit("update:msg2", "新的msg2")
}
</script>
插槽 slots
插槽可以理解为父组件传一段
HTML
片段给子组件。子组件将<slot>
元素作为承载分发内容的出口
provide / inject
跨层级组件通信,不限层级
顶级组件A:
<script setup lang='ts'>
import { provide } from "vue";
provide("username", "aaa");
</script>
顶级组件B:
<script setup lang='ts'>
import { provide } from "vue";
provide("username", "bbb");
</script>
底层组件:
<script setup lang='ts'>
import { inject } from "vue";
const username = inject("username");
console.log(username);
</script>
Vuex / Pinia
mitt
父子、兄弟、跨层级组件通信
详见官方示例
安装:
$ npm install --save mitt
封装mitt.ts
:
import mitt from 'mitt'
const Mitt =mitt()
export default Mitt
父组件:
<template>
<Child1 />
<Child2 />
</template>
子组件 Child1:
<template>
子组件1
<button @click="handleClick">打声招呼</button>
</template>
<script setup lang="ts">
import Mitt from '@/utils/mitt';
function handleClick() {
Mitt.emit('sayHello')
}
</script>
子组件 Child2:
<template>
子组件2
</template>
<script setup lang="ts">
import Mitt from '@/utils/mitt'
Mitt.on('sayHello', () => console.log('兄弟你好'))
</script>