在 Vue 3 中,setup
函数是 Vue 3 中的 Composition API 的核心,它提供了一种更灵活的方式来定义组件逻辑。props
和 emit
是父子组件通信的基础,通过 setup
函数,这些机制得到了更简化的实现。Vue 3 中的 emits
事件管理也变得更加结构化。
一、setup
下的 props
和 emit
在 setup
函数中,props
是以参数的形式传递给组件,而 emit
事件函数也是通过参数获取的。我们来看看如何使用它们。
1. 父组件传递 props
在 Vue 3 中,父组件通过 props
向子组件传递数据的方式没有改变,仍然是在子组件标签上使用绑定的方式传递数据。
父组件代码:
<template>
<div>
<h1>父组件</h1>
<ChildComponent :message="parentMessage" :count="parentCount" @child-event="handleChildEvent"></ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() {
return {
parentMessage: 'Hello from parent!',
parentCount: 10
};
},
methods: {
handleChildEvent(payload) {
console.log('父组件接收到的子组件事件数据:', payload);
}
}
};
</script>
在这个例子中,父组件传递了 message
和 count
给子组件。
2. 子组件接收 props
和触发 emit
在 setup
函数中,props
和 emit
通过参数接收。emit
可以触发自定义事件,将数据传递给父组件。
子组件代码:
<template>
<div>
<h2>子组件</h2>
<p>Message from parent: {{ message }}</p>
<p>Count from parent: {{ count }}</p>
<button @click="sendMessage">向父组件发送事件</button>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
props: {
message: String,
count: Number,
},
setup(props, { emit }) {
const sendMessage = () => {
emit('child-event', 'Hello from Child');
};
return { props, sendMessage };
}
});
</script>
在 setup
函数中,我们通过参数接收了 props
,并定义了一个 sendMessage
函数,通过 emit
触发自定义事件 child-event
,将数据传递给父组件。
二、emits
事件管理
在 Vue 3 中,emits
选项允许我们显式地定义子组件会触发哪些事件,这是一种增强的事件管理方式。
1. emits
选项
在子组件中,我们可以通过 emits
选项来定义组件可以触发的事件。这样做的好处是,可以对事件进行更好的文档化和管理,也可以对事件触发进行校验。
<script>
import { defineComponent } from 'vue';
export default defineComponent({
props: {
message: String,
count: Number,
},
emits: ['child-event'], // 定义子组件将会触发的事件
setup(props, { emit }) {
const sendMessage = () => {
emit('child-event', 'Hello from Child'); // 触发事件
};
return { props, sendMessage };
}
});
</script>
2. 事件校验
emits
选项不仅能定义事件,还可以为事件添加校验逻辑。我们可以通过函数校验事件的参数是否符合预期。
<script>
import { defineComponent } from 'vue';
export default defineComponent({
props: {
message: String,
count: Number,
},
emits: {
'child-event': (payload) => {
return typeof payload === 'string'; // 校验事件参数必须是字符串
}
},
setup(props, { emit }) {
const sendMessage = () => {
emit('child-event', 'Hello from Child');
};
return { props, sendMessage };
}
});
</script>
在这个示例中,emits
选项中为 child-event
事件定义了一个校验函数,只有当事件参数是字符串时,事件才会被触发。
三、setup
下的原理解析
1. props
原理
在 setup
中接收的 props
是响应式的,这意味着当父组件传递的 props
数据变化时,子组件会自动更新。
- 在
setup
中接收到的props
是不可直接解构的,否则将失去响应式能力。如果需要解构,可以使用toRefs
或toRef
。
import { toRefs } from 'vue';
setup(props) {
const { message, count } = toRefs(props); // 解构成响应式变量
return { message, count };
}
2. emit
原理
emit
函数是 Vue 内置的事件触发机制,它允许组件触发自定义事件,并将数据传递给父组件。Vue 内部会根据 emits
选项确保事件是有效的并调用父组件的监听器。
四、示例:父子组件通信
我们通过一个简单的例子,展示 props
和 emit
在 setup
下的具体应用。
父组件:
<template>
<div>
<h1>父组件</h1>
<p>Count: {{ parentCount }}</p>
<ChildComponent :count="parentCount" @update-count="handleUpdateCount"></ChildComponent>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() {
return {
parentCount: 0
};
},
methods: {
handleUpdateCount(newCount) {
this.parentCount = newCount;
}
}
};
</script>
子组件:
<template>
<div>
<h2>子组件</h2>
<p>当前计数: {{ count }}</p>
<button @click="increment">增加计数</button>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
props: {
count: Number,
},
emits: ['update-count'],
setup(props, { emit }) {
const increment = () => {
emit('update-count', props.count + 1);
};
return { increment };
}
});
</script>
总结
props
:setup
函数中props
是通过参数传递的,不能直接解构,否则会丧失响应性。emit
:emit
函数可以触发事件,父组件通过监听子组件的自定义事件来实现双向数据交互。emits
:在 Vue 3 中,可以通过emits
选项来显式定义组件的事件,并且可以进行参数校验。
Vue 3 的 setup
和 emits
机制使组件通信变得更加简洁和灵活,同时也增强了代码的可读性和可维护性。