一、Props传递静态数据
defineProps() 和 defineEmits()
为了在声明
props
和emits
选项时获得完整的类型推导支持,我们可以使用defineProps
和defineEmits
API,它们将自动地在<script setup>
中可用:
defineProps
和defineEmits
都是只能在<script setup>
中使用的编译器宏。他们不需要导入,且会随着<script setup>
的处理过程一同被编译掉。
defineProps
接收与props
选项相同的值,defineEmits
接收与emits
选项相同的值。
defineProps
和defineEmits
在选项传入后,会提供恰当的类型推导。
SupComponent.vue
<template><div><h1>子组件</h1>{{username}} ,{{address}}</div>
</template><script setup>defineProps(['username',"address"])
</script><style>
</style>
MyParentComponent.vue
<template><div><p></p><SubComponent username="张飞飞" address="北京市"></SubComponent></div>
</template><script setup>// 引入组件import SubComponent from './SubComponent.vue';</script>
二、Props传递动态数据
注意:Props传递动态数据时,我们需要借助v-bind指令或缩写
:
来进行动态绑定的 props:这里我们采用的是其简写形式。
<SubComponent :username="msg" :address="addr"></SubComponent></div>
</template><script setup>import {ref} from 'vue'// 引入组件import SubComponent from './SubComponent.vue';const msg=ref('米克')const addr=ref('杭州市')</script>
除了使用字符串,还可以使用一个对象绑定多个 prop
三、单向数据流
所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。
另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告:
如果需要更改 prop 有以下两种场景:
<script setup>import {ref,computed} from 'vue'const props=defineProps({count:{type:Number,default: 1 // Number 类型的默认值},size:{type:String,default: 'book' //默认值}})
1、prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。
// 只是将 props.count 作为初始值// 像下面这样做就使 prop 和后续更新无关了const mycount=ref(props.count)
2、需要对传入的 prop 值做进一步的转换。在这种情况中,最好是基于该 prop 值定义一个计算属性:
// 该 prop 变更时计算属性也会自动更新const mySize = computed(() => props.size.trim().toUpperCase())
四、props校验
props主要目的:为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误
props语法
props: {校验的属性名:类型 // Stirng | Number | Object | Array | Boolean | Functionlist:Array, // 表示只校验类型,类型是数组即可say:Function, // 表示只校验类型,类型是函数即可 }
- 类型校验
- 非空校验
- 默认值
- 自定义校验
props: {校验的属性名: {type: 类型, // Number String Boolean ...required: true, // 是否必填default: 默认值, // 默认值validator (value) {// 自定义校验逻辑return 是否通过校验}} },
子组件Children.vue
<template><div>{{username}} {{age}} {{flag}} <br/><br/>{{hobby}} <br/><br/>{{emp}} <br/><br/></div>
</template>// 注意:必须使用setup,否则不能渲染
<script setup>
import {ref,computed} from 'vue'
const props=defineProps({username:{type:String,required: true //父组件,必须传递值},age:{type:[Number,String], // 传递过来的数据,可以是数字或字符串default: 18 //如果父组件不传,则默认值},flag:{type:Boolean},hobby:Array, // 表示只校验类型,类型是数组即可emp:{default:()=>{return{} // 对于默认值是数组或对象的情况,默认值要写一个函数,函数中返回默认值}},show:Function // 表示只校验类型,类型是函数即可 })
</script><style>
</style>
父组件Mother.vue
<template><div><p></p><Children username="mike":age="re.age":flag="re.flag":hobby="re.hobby":emp="re.emp":show="re.show"></Children></div>
</template><script setup>import Children from "./Children.vue"import {ref,reactive} from 'vue'//父传子的类型数据const re = reactive({ age:20, flag: true, hobby: ['play','sleep','read'],emp:{name:'john',gender:'man'},show(){console.log('I am props!')}})
</script>
注意:
1.default和required一般不同时写(因为当时必填项时,肯定是有值的)
2.default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值