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

Vue/Vuetify中点击按钮后点击事件丢失问题求助

生产环境下Vuetify弹窗仅能打开一次的问题排查

问题现象

  • 基于Vuetify开发的弹窗组件,通过按钮触发打开,完成操作后可关闭
  • 开发环境:关闭弹窗后可再次正常打开
  • 生产环境:弹窗仅能打开一次,首次点击按钮后DOM/Window上的点击事件被移除

技术栈

  • Vue 2
  • Vuetify 2.7
  • 项目包含部分旧jQuery代码

排查线索

  • 打开弹窗时整个组件会触发重渲染
  • 移除弹窗标签页中加载的所有组件后,问题不再出现

弹窗容器代码

<template>
  <div>
    <v-tooltip left>
      <template #activator="{ on, attrs }">
        <v-btn
          class="o-page-sidebar__button create-project__button"
          color="#009688"
          dark
          depressed
          tile
          v-bind="attrs"
          v-on="on"
          @click="triggerModal(undefined)"
        >
          <v-icon size="16">
            fal fa-clipboard-list
          </v-icon>
        </v-btn>
      </template>
      <span>{{ translations.title }}</span>
    </v-tooltip>

    <CreateProjectModal
      v-if="showModal"
      v-bind="$attrs"
      v-model="showModal"
      :translations="translations"
      @hasEditedProject="handleHasEditedProject"
      @hasCreatedProject="handleHasCreatedProject"
    />
  </div>
</template>

<script>
export default {
  data() {
    return {
      showModal: false,
    };
  },
  methods: {
    triggerModal(eventObject) {
      if (eventObject == undefined) {
        eventObject = {};
      }

      const localStorageValue = localStorage.useNewCreateProjectDialog != undefined ? localStorage.useNewCreateProjectDialog == 'true' : true;

      const openRequest = {
        Type: eventObject.type,
        ProjectID: eventObject.projectID,
        OfferID: eventObject.offerID,
        DebtorID: eventObject.debtorID,
        FitterID: eventObject.fitterID,
        ManagerID: eventObject.managerID,
        PlanningStartDate: eventObject.planningStartDate,
        PlanningEndDate: eventObject.planningEndDate
      };

      this.notification.show = false;

      if (localStorageValue) {
        const type = eventObject.type ? eventObject.type : 'CreateProject';

        openRequest.Type = this.openProjectDialogEnum.find(x => x.Name == type)?.Name;

        this.$store.dispatch('setOpenRequest', openRequest);

        this.$store.dispatch('setHasInitializedFields', {
          'MainProjectID': false,
          'OfferID': false,
          'ProjectDebtorID': openRequest.Type != 'EditProject',
          'ProjectGroupID': openRequest.Type != 'EditProject'
        });

        this.showModal = true;
      }
    }
}
</script>

弹窗组件代码

<template>
  <v-dialog
    v-model="show"
    :class="{ 'new-create-project' : show }"
    fullscreen
    :retain-focus="false"
    hide-overlay
    persistent
    no-click-animation
    height="100vh"
    transition="dialog-bottom-transition"
    @keydown.esc="confirmClose"
  >
    {{ ... }}
  </v-dialog>
</template>

<script>
export default {
  props: {
    value: {
      type: Boolean,
      default: false
    },
  },
  computed: {
    show: {
      get() {
        return this.value;
      },
      set(value) {
        if (!value) {
          this.$store.dispatch('setNotifications', []);
          this.$store.dispatch('setSelectedDebtor', null);
          this.$store.dispatch('emptyErrors');
        }

        this.$store.dispatch('resetProjectData');
        this.$emit('input', value);
      }
    },
  }
}
</script>

标签页加载代码

<v-tabs
          ref="tabs"
          v-model="currentTab"
          v-shortkey.once="{save: ['ctrl', 'q'], saveAndPrint: ['alt', 'q'], tabRight: ['alt', 'arrowright'], tabLeft: ['alt', 'arrowleft']}"
          grow
          @shortkey.native="handleShortcuts"
        >
          <v-tab
            v-for="(tab, i) in mappedTabs"
            :key="i"
            :disabled="(tab.canDisable && !enableTabs) || tab.disabled"
          >
            <v-icon left>
              {{ tab.icon }}
            </v-icon>
            {{ tab.name }}
            <v-icon
              v-if="tab.hasErrors"
              size="14"
              color="error"
              class="ml-2"
            >
             fa fa-exclamation-triangle
            </v-icon>
          </v-tab>
        </v-tabs>
      </v-card-text>

      <v-tabs-items
        v-model="currentTab"
        class="grow d-grid"
      >
        <v-card-text class="fill-height">
          <v-tab-item
            v-for="(tab, i) in mappedTabs"
            :key="`${i}-item`"
            class="fill-height"
          >
            <component
              :is="tab.component"
              :is-active="currentTab === i"
              v-bind="$attrs"
              from-create-project
              class="create-project__form"
              @show-association="showAssociation"
              @set-contact-person="setContactPerson"
              @set-work-address="setWorkAddress"
            />
          </v-tab-item>
        </v-card-text>
      </v-tabs-items>

标签页示例代码

{
   name: this.translations.tabProjectInformation,
   hasErrors: this.$store.getters.hasProjectInformationErrors,
   icon: 'fal fa-clipboard-list',
   component: 'ProjectInformation'
 },

内容的提问来源于stack exchange,提问作者Ayice

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:02:02