在 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 机制使组件通信变得更加简洁和灵活,同时也增强了代码的可读性和可维护性。