Vue.js事件透传异常:点击按钮同时触发click与命名事件
VueFormulate事件透传冲突问题解决办法
问题说明
我用VueFormulate通过JSON Schema生成表单,想不用修改通用组件就能添加任意事件监听器,所以用v-on="$listeners"做事件透传。但因为要在传递表单对象前做数据处理,自己指定了save、submit这类事件。现在遇到的问题:
- 点击触发
save事件的按钮时,父组件会同时收到save和click事件,且二者都会触发父组件的save事件监听器; - 移除
v-on="$listeners"后,自定义的save、submit事件能正常工作,但JSON Schema里定义的其他事件(比如showPreview、cancel)又没法透传给父组件。
问题原因
v-on="$listeners"会把父组件绑定的所有事件监听器全量透传给FormulateForm,包括我们已经手动处理的save、submit。当点击Schema里定义的按钮时:
- 按钮会触发指定的事件(比如
save),被$listeners中父组件的save监听器捕获; - 我们自定义的
handleSave方法又会主动emit一次save事件; - 同时按钮的原生
click事件也会被透传,导致多个事件触发同一监听器的情况。
解决方案
手动过滤$listeners,把已经在组件中自定义处理的事件从透传列表中移除,既保留Schema中其他事件的透传能力,又避免自定义事件重复触发。
修改后的代码示例
Dynamic-form.vue
<template> <div> <FormulateForm :name="name" v-model="theForm" :schema="filteredFormSchema" @submit="handleSubmit" @save="handleSave" v-on="filteredListeners" > </FormulateForm> </div> </template> <script> import "./vue-formulate-config" import { cloneDeep } from "lodash"; export default { name: "DynamicForm", props: { formSchema: { type: Array, required: true, }, formData: { type: Object, required: true, }, name: { type: String, default: 'theForm' }, hideOptionalFields: { type: Boolean, default: false } }, data() { return { theForm: {}, schema: [], }; }, computed: { filteredListeners() { // 移除已手动处理的事件,防止重复触发 const handledEvents = ['save', 'submit']; return Object.keys(this.$listeners).reduce((acc, event) => { if (!handledEvents.includes(event)) { acc[event] = this.$listeners[event]; } return acc; }, {}); }, filteredFormSchema() { // 这里保留你原有的Schema过滤逻辑,比如处理隐藏可选字段 return this.formSchema; } }, methods: { generateFormData(formValues) { // 你的表单数据处理逻辑 return formValues; }, handleSave() { this.$emit("save", this.generateFormData(this.theForm)); }, handleSubmit(formValues) { this.$emit("submit", this.generateFormData(formValues)); }, }, }; </script>
效果说明
filteredListeners会自动过滤掉save、submit事件,只透传父组件绑定的showPreview、cancel等其他事件;- 点击Schema中的按钮时,自定义的
save、submit事件只会触发一次,父组件不会收到重复事件; - Schema中定义的其他事件(比如
showPreview、cancel)依然能正常透传给父组件,无需修改通用组件即可添加任意事件监听器。
内容的提问来源于stack exchange,提问作者Jmh2013
相关产品推荐
相关产品推荐

