编译期宏函数特点:不用导入、只在 setup 语法糖里用、打包会删掉
defineProps
接收父组件传参
vue
<script setup>
// 简单版
const props = defineProps(['name','age'])
// 严谨版
const props = defineProps({
name: String,
age: {
type: Number,
default: 18,
required: false
}
})
</script>useAttrs
useAttrs() 函数用于接收父组件向子组件传递但是并没有被 defineProps 接收的属性
父组件
vue
<template>
<!-- 传了class、data-id、title,子组件props只接了title -->
<MyCard
title="我是标题"
class="red-card"
data-id="666"
/>
</template>子组件
vue
<template>
<!-- 把attrs所有属性绑到根div上 -->
<div v-bind="attrs">{{ props.title }}</div>
</template>
<script setup>
import { useAttrs } from 'vue'
// 只接收 title
const props = defineProps(['title'])
// 剩下 class/data-id 全都进 attrs
const attrs = useAttrs()
console.log(attrs)
// { class: "red-card", dataId: "666" }
</script>知识点
- 属性会自动驼峰:
data-id→dataId inheritAttrs: true(默认):Vue 自动把 attrs 挂到根标签;设为false就要手动v-bind="attrs"
defineEmits
声明自定义事件
vue
<script setup>
const emit = defineEmits(['submit','update:selectedAnswers'])
// 触发
emit('update:selectedAnswers', [1,2,3])
</script>defineModel
Vue3.4+ 极简 v-model
vue
<script setup>
// 默认 v-model
const val = defineModel()
// 命名参数 → 对应 v-model:selectedAnswers
const selectedAnswers = defineModel('selectedAnswers',{
default: ()=>[]
})
// 直接改,自动双向同步
selectedAnswers.value.push(1)
</script>defineExpose
暴露子组件 属性/方法 给父 ref
vue
<script setup>
const count = ref(0)
const add = ()=>count.value++
defineExpose({ count, add })
</script>defineOptions
配置组件原生选项
vue
<script setup>
defineOptions({
name: "QuestionComp", // 组件名
inheritAttrs: false // 关闭class/style自动透传
})
</script>defineSlots
TS 专属:约束插槽类型
vue
<script setup lang="ts">
defineSlots<{
// 默认插槽:必须传 row、index 参数
default: (props: { row: string; index: number }) => any
// header插槽:可选,无参数
header?: () => any
// footer插槽:可选,带count参数
footer?: (props: { count: number }) => any
}>()
</script>useSlots
useSlots() 函数用于在 JS 代码里,看父组件有没有传某个插槽
父组件
vue
<template>
<MyCard>
<!-- 传了header插槽 -->
<template #header>自定义头部</template>
默认内容
</MyCard>
</template>子组件
vue
<template>
<div>
<!-- 有header插槽就渲染,没有就显示默认 -->
<div v-if="slots.header">
<slot name="header"></slot>
</div>
<div v-else>默认头部标题</div>
<slot></slot>
</div>
</template>
<script setup>
import { useSlots } from 'vue'
// 获取所有插槽对象
const slots = useSlots()
// JS里判断:是否存在header插槽
console.log(!!slots.header) // true
</script>