父子组件通信
defineProps父组件向子组件传值
defineProps
是一个仅 <script setup>
中可用的编译宏命令,并不需要显式地导入。声明的 props 会自动暴露给模板。defineProps
会返回一个对象,其中包含了可以传递给组件的所有 props:
<MyComponent v-model:foo="foo" />
const foo = ref(1)
<script setup>
const props = defineProps(['foo'])
console.log(props.foo)
</script>
defineProps({
// 基础类型检查
// (给出 `null` 和 `undefined` 值则会跳过任何类型检查)
propA: Number,
// 多种可能的类型
propB: [String, Number],
// 必传,且为 String 类型
propC: {
type: String,
required: true
},
// Number 类型的默认值
propD: {
type: Number,
default: 100
},
// 对象类型的默认值
propE: {
type: Object,
// 对象或数组的默认值
// 必须从一个工厂函数返回。
// 该函数接收组件所接收到的原始 prop 作为参数。
default(rawProps) {
return { message: 'hello' }
}
},
// 自定义类型校验函数
propF: {
validator(value) {
// The value must match one of these strings
return ['success', 'warning', 'danger'].includes(value)
}
},
// 函数类型的默认值
propG: {
type: Function,
// 不像对象或数组的默认,这不是一个
// 工厂函数。这会是一个用来作为默认值的函数
default() {
return 'Default function'
}
}
})
一些补充细节:
- 所有 prop 默认都是可选的,除非声明了
required: true
。 - 除
Boolean
外的未传递的可选 prop 将会有一个默认值undefined
。 Boolean
类型的未传递 prop 将被转换为false
。这可以通过为它设置default
来更改——例如:设置为default: undefined
将与非布尔类型的 prop 的行为保持一致。- 如果声明了
default
值,那么在 prop 的值被解析为undefined
时,无论 prop 是未被传递还是显式指明的undefined
,都会改为default
值。
子组件向父组件传值/触发事件
defineEmits触发父组件事件
可以通过defineEmits宏来声明需要抛出的事件
<script setup>
import { ref } from 'vue'
import BlogPost from './BlogPost.vue'
</script>
<template>
<div :style="{ fontSize: postFontSize + 'em' }">
<BlogPost
@enlarge-text="postFontSize += 0.1"
></BlogPost>
</div>
</template>
<script setup>
defineEmits(['enlarge-text'])
</script>
<template>
<div class="blog-post">
<button @click="$emit('enlarge-text')">Enlarge text</button>
</div>
</template>
defineEmits向父组件传值
子组件的传递方式
<template>
<button @click="clickChild">点击子组件</button>
</template>
<script setup>
import { defineEmits } from 'vue'
// 使用defineEmits创建名称,接受一个数组
const emit = defineEmits(['clickChild'])
const clickChild=()=>{
//传递给父组件
emit('clickChild',{content:'b'})
}
</script>
父组件接收与使用
<template>
<div class="hello">
<!-- clickChild是子组件绑定的事件,click是父组件接受方式 -->
<Child @clickChild="clickEven"></Child>
<p>子组件传递的值是 {{result}}</p>
</div>
</template>
<script setup>
import Child from './Child'
import {ref} from 'vue'
const result=ref('')
const clickEven=(val)=>{
result.value=val.content
console.log("触发了父组件方法")
}
</script>
双向绑定 prop
emit-update
3.4 之前的用法
<script setup>
defineProps({
firstName: String,
lastName: String
})
defineEmits(['update:firstName', 'update:lastName'])
</script>
<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
通过触发 update:title
事件更新父组件值
defineModel
这个宏可以用来声明一个双向绑定 prop
// 声明 "modelValue" prop,由父组件通过 v-model 使用
const model = defineModel()
// 或者:声明带选项的 "modelValue" prop
const model = defineModel({ type: String })
// 在被修改时,触发 "update:modelValue" 事件
model.value = "hello"
// 声明 "count" prop,由父组件通过 v-model:count 使用
const count = defineModel("count")
// 或者:声明带选项的 "count" prop
const count = defineModel("count", { type: Number, default: 0 })
function inc() {
// 在被修改时,触发 "update:count" 事件
count.value++
}
如果为 defineModel
prop 设置了一个 default
值且父组件没有为该 prop 提供任何值,会导致父组件与子组件之间不同步。在下面的示例中,父组件的 myRef
是 undefined,而子组件的 model
是 1:
// 子组件:
const model = defineModel({ default: 1 })
// 父组件
const myRef = ref()
<Child v-model="myRef"></Child>
ref父组件获取子组件的属性/方法
当时用语法糖时,需要将组建的属性及方法通过defineExpose导出,父组件才能访问到数据,否则拿不到子组件的数据
子组件的传递方式
<template>
<div>
<h2> 我是子组件</h2>
<p>性别:{{ sex}}</p>
</div>
</template>
<script setup>
import { reactive, ref,defineExpose } from "vue";
let sex=ref('男')
let info=reactive({
like:'王者荣耀',
age:18
})
defineExpose({sex, info})
</script>
<style>
</style>
父组件显示方式
<template>
<div class="hello">
我是父组件
<Child ref="testcomRef"></Child>
<button @click="getSonHander">获取子组件中的数据</button>
</div>
</template>
<script setup>
import Child from './Child'
import {ref} from 'vue'
const testcomRef = ref()
const getSonHander=()=>{
console.log('获取子组件中的性别', testcomRef.value.sex );
console.log('获取子组件中的其他信息', testcomRef.value.info )
}
</script>
<style scoped>
</style>