-
defineProps
和defineEmits
都是只能在<script setup>
中使用的编译器宏。他们不需要导入,且会随着<script setup>
的处理过程一同被编译掉。 -
defineProps
接收与props
选项相同的值,defineEmits
接收与emits
选项相同的值。
父传子 - defineProps
父组件
<template>
<div class="Father">
<p>我是父组件</p>
<!-- -->
<son :ftext="ftext"></son>
</div>
</template>
<script setup>
import {ref} from 'vue'
import Son from './son.vue'
const ftext = ref('我是父组件-text')
</script>
子组件
<template>
<div class="Son">
<p>我是子组件</p>
<!-- 展示来自父组件的值 -->
<p>接收到的值:{
{ftext}}</p>
</div>
</template>
<script setup>
import {ref} from 'vue'
// setup 语法糖写法
//defineProps 来接收组件的传值
const props = defineProps({
ftext: {
type:String
},
})
</script>
组件名格式
都使用 PascalCase 作为组件名的注册格式(每个字母开头大写)
<ComponentA></ComponentA>
import ComponentA from './ComponentA.js'
export default {
components: {
ComponentA
},
setup() {
// ...
}
}
传递 prop 的细节
Prop 名字格式:如果一个 prop 的名字很长,应使用 camelCase 形式(即驼峰命名法)
在子组件里的defineProps使用 camelCase 形式(即驼峰命名法)
//子组件里使用
defineProps({
greetingMessage: String
})
<span>{
{ greetingMessage }}</span>
虽然理论上你也可以在向子组件传递 props 时使用 camelCase 形式 (使用 DOM 内模板时例外),但实际上为了和 HTML attribute 对齐,我们通常会将其写为 kebab-case 形式(即单词连接命名法 greeting-message):
在父组件里引用子组件且传递参数时 使用 kebab-case 形式
//父组件
<MyComponent greeting-message="hello" />
子传父 - defineEmits
子组件:
<template>
<div class="Son">
<p>我是子组件</p>
<button @click="toValue">点击给父组件传值</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
// setup 语法糖写法
//用defineEmits()来定义子组件要抛出的方法,语法defineEmits(['要抛出的方法'])
const emit = defineEmits(['exposeData'])
const stext = ref('我是子组件的值-ftext')
const toValue = ()=>{
emit('exposeData',stext)
}
</script>
父组件:
<template>
<div class="Father">
<p>我是父组件</p>
<!-- -->
<son @exposeData="getData" :ftext="ftext"></son>
</div>
</template>
<script setup>
import {ref} from 'vue'
import Son from './son.vue'
const ftext = ref('我是父组件-text')
const getData = (val)=>{
console.log("接收子组件的值",val)
}
</script>
defineExpose
使用 <script setup>
的组件是默认关闭的(即通过模板引用或者 $parent
链获取到的组件的公开实例,不会暴露任何在 <script setup>
中声明的绑定)。
可以通过 defineExpose
编译器宏来显式指定在 <script setup>
组件中要暴露出去的属性
子组件:
<template>
<div>
<p>我是子组件</p>
</div>
</template>
<script setup>
import { ref } from 'vue';
const stext = ref('我是子组件的值')
const sfunction = ()=>{
console.log("我是子组件的方法")
}
defineExpose({
stext,
sfunction
})
</script>
父组件:
<template>
<div class="todo-container">
<p>我是父组件</p>
<son ref="sonDom"></son>
<button @click="getSonDom">点击</button>
</div>
</template>
<script setup>
import { ref ,nextTick} from 'vue';
import son from './components/son.vue'
const sonDom = ref(null) //注意这里的命名要和ref上面的命名一致
const getSonDom = ()=>{
console.log("sonDom",sonDom.value)
}
//直接打印sonDom的值是拿不到的,子组件节点还没生成
nextTick(()=>{
console.log("sonDom",sonDom.value)
})
</script>
参考文档: <script setup> | Vue.js
上面所说的都是常规的父子组件(一级嵌套),如果出现多层的嵌套,那么使用props传参很麻烦。
provide
和inject
可以帮助我们解决这一问题 [1]。一个父组件相对于其所有的后代组件,会作为依赖提供者。任何后代的组件树,无论层级有多深,都可以注入由父组件提供给整条链路的依赖。
参考文档:依赖注入 | Vue.js