一、接受参数
1、接受父组件参数:Props
export default {
props: ['foo'],
setup(props) {
console.log(props.foo)
}
}
2、接受父组件参数:defineProps 宏
- 在使用
<script setup>的单文件组件中,props 可以使用 defineProps() 宏来声明
<script setup>
const props = defineProps(['foo'])
console.log(props.foo)
</script>
- 如果一个
prop 的名字很长,应使用 camelCase 形式命名,但实际上为了和 HTML attribute 对齐,我们通常会将其写为 kebab-case 形式
<MyComponent greeting-message="hello" />
defineProps({
greetingMessage: String
})
- 所有的 props 都遵循着
单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。
- 每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你
不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告:
- 你想要更改一个 prop 的需求通常来源于以下两种场景
- 1、prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性。在这种情况下,最好是新定义一个局部数据属性,从 props 上获取初始值即可:
const props = defineProps(['initialCounter'])
const counter = ref(props.initialCounter)
- 2、需要对传入的 prop 值做进一步的转换。在这种情况中,最好是基于该 prop 值定义一个计算属性:
const props = defineProps(['size'])
const normalizedSize = computed(() => props.size.trim().toLowerCase())
- 3、更改对象 / 数组类型的 props
- 当对象或数组作为 props 被传入时,虽然子组件无法更改 props 绑定,但仍然可以更改对象或数组内部的值。这是因为 JavaScript 的对象和数组是按引用传递,对 Vue 来说,阻止这种更改需要付出的代价异常昂贵。你应该尽可能避免这样的更改,除非父子组件在设计上本来就需要紧密耦合。
- 4、校验
defineProps({
propA: Number,
propB: [String, Number],
propC: {
type: String,
required: true
},
propD: {
type: [String, null],
required: true
},
propE: {
type: Number,
default: 100
},
propF: {
type: Object,
default(rawProps) {
return { message: 'hello' }
}
},
propG: {
validator(value, props) {
return ['success', 'warning', 'danger'].includes(value)
}
},
propH: {
type: Function,
default() {
return 'Default function'
}
}
})
二、接受事件和触发事件
1、接受父组件事件:defineEmits 宏
defineEmits 仅可用于<script setup> 之中,我们可以通过 defineEmits 宏来声明需要抛出的事件
- 方式1
<template>
<div class="blog-post">
<button @click="$emit('enlarge-text')">Enlarge text</button>
</div>
</template>
<script setup>
defineEmits(['enlarge-text'])
</script>
- defineEmits并且不需要导入,它返回一个等同于 $emit 方法的 emit 函数
- 方式2
<script setup>
const emit = defineEmits(['enlarge-text','enlarges'])
emit('enlarge-text');
</script>
- 如果你没有在使用 <script setup>,你可以通过 emits 选项定义组件会抛出的事件。你可以从 setup() 函数的第二个参数,即 setup 上下文对象上访问到 emit 函数
- 方式3
<script>
export default {
emits: ['enlarge-text'],
setup(props, ctx) {
ctx.emit('enlarge-text')
}
}
</script>
2、接受父组件事件:emits
- 如果你显式地使用了
setup 函数,则事件需要通过 emits选项来定义,emit 函数也被暴露在 setup() 的上下文对象上
export default {
emits: ['inFocus', 'submit'],
setup(props, ctx) {
ctx.emit('submit')
}
}
3、触发事件:emit
暴露属性和函数给父组件
1、defineExpose
- 原理:使用
<script setup> 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。
- 作用:用于组件通信中父级组件调用操作子组建方法和响应式属性参数能力,即子组件将值和方法传给父组件,父组件通过ref属性获取子组件暴露的。
- ref会和在普通实例中一样被自动解包,父组件无需使用.value
2、子组件
<script setup>
import {ref} from "vue";
function childFn() { }
let msg = 'Hello World';
defineExpose({
msg,
childFn,
});
</script>
3、父组件
<Index ref="childeRef"></Index>
<script setup>
import Index from "./index.vue";
const childeRef = ref();
onMounted(() => {
childeRef.value.childFn()
childeRef.value.msg = 'Hello 1234'()
})
</script>