父组件传值给子组件(简称:父传子) defineProps
// 父组件
<template>
<!-- 使用子组件 -->
<Child :msg="message" />
</template>
<script setup>
import Child from './Child.vue' // 引入子组件
let message = '你好 vue3'
</script>
// 子组件
<template>
<div>
{{ msg }}
</div>
</template>
<script setup>
const props = defineProps({
msg: {
type: String,
default: ''
}
})
console.log(props.msg) // 打印需要使用 props.msg,在html中使用只需要 {{props}}
</script>
defineProps 其实还能做很多事情,比如:设置默认值 default ,类型验证 type ,要求必传 required ,自定义验证函数 validator 等等。 它在 script setup 中是直接可用不需要额外引入。更多细节请看文档。
官网地址: props 文档
子组件通知父组件触发一个事件并且传值给父组件。(简称:子传父)defineEmits
// 父组件
<template>
<div>父组件:{{ message }}</div>
<!-- 自定义 changeMsg 事件 -->
<Child @changeMsg="changeMessage" />
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
let message = ref('Hello vue3')
// 更改 message 的值,data是从子组件传过来的
const changeMessage = (data) => {
message.value = data
}
</script>
// 子组件
<template>
<div>
子组件:<button @click="handleClick">子组件的按钮</button>
</div>
</template>
<script setup>
// 注册一个自定义事件名,向上传递时告诉父组件要触发的事件。
const emit = defineEmits(['changeMsg'])
const handleClick = ()=> {
// 参数1:事件名
// 参数2:传给父组件的值
emit('changeMsg', '你好 vue3')
}
</script>
和 defineProps 一样,在 script setup 中必须使用 defineEmits API 来声明 emits,它在 script setup 中是直接可用不需要额外引入。更多细节请看文档。
官网地址: emits文档
expose 导出 / ref 获取
// 父组件
<template>
<div>父组件:拿到子组件的msg数据:{{ msg }}</div>
<button @click="callChildFn">调用子组件的方法</button>
<Child ref="com" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'
const com = ref(null) // 通过 模板ref 绑定子组件
const msg = ref('')
onMounted(() => {
// 在加载完成后,将子组件的 message 赋值给 msg
msg.value = com.value.message
})
const callChildFn = ()=> {
// 调用子组件的 changeMessage 方法
com.value.changeMessage('你好 vue3')
// 重新将 子组件的message 赋值给 msg
msg.value = com.value.message
}
</script>
// 子组件
<template>
<div>子组件:{{ message }}</div>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('Hello vue3')
const changeMessage = (data)=> {
message.value = data
}
使用 defineExpose 向外暴露指定的数据和方法
defineExpose({
message,
changeMessage
})
</script>
provide / inject 多层级传递
provide 是在父组件里使用的,可以往下传值。
inject 是在子(后代)组件里使用的,可以网上取值。
provide / inject 文档
// 父组件
<template>
<Child></Child>
</template>
<script setup>
import { ref, provide, readonly } from 'vue'
import Child from './Child.vue'
const name = ref('往下')
const msg = ref('你好 vue3')
// 使用readonly可以让子组件无法直接修改,需要调用provide往下传的方法来修改
provide('name', readonly(name))
provide('msg', msg)
provide('changeName', (value) => {
name.value = value
})
</script>
// 在不知道要多少层的子组件下调用参数
<template>
<div>
<div>msg: {{ msg }}</div>
<div>name: {{name}}</div>
<button @click="handleClick">修改</button>
</div>
</template>
<script setup>
import { inject } from 'vue'
const name = inject('name', 'hello') // 看看有没有值,没值的话就适用默认值(这里默认值是hello)
const msg = inject('msg')
const changeName = inject('changeName')
const handleClick ()=> {
// 子组件
// name.value = 'vue3'
// 这样写不行,因为vue里推荐使用单向数据流,当父级使用readonly后,这行代码是不会生效的。
// 正确的方式
changeName('再往下')
// 因为 msg 没被 readonly 过,所以可以直接修改值
msg.value = 'Hello'
}
</script>