You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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里定义的按钮时:

  1. 按钮会触发指定的事件(比如save),被$listeners中父组件的save监听器捕获;
  2. 我们自定义的handleSave方法又会主动emit一次save事件;
  3. 同时按钮的原生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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:55:35