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

Vue组件中列表项点击事件滞后于容器隐藏的问题解决咨询

解决Vue中列表项点击事件被blur事件抢先触发的问题

你遇到的问题核心是事件触发顺序:当点击列表项时,input的blur事件会先于列表项的click事件执行——blur触发后toggle变为false,列表被隐藏,导致click事件根本没机会触发。下面给你几个实用的解决方案:

方案一:用mousedown替代click事件

mousedown事件的触发时机早于blur,所以能在列表被隐藏前完成赋值操作。只需要把按钮的@click换成@mousedown即可:

<template>
  <div class="Container">
    <input ref="input" type="text" :placeholder="placeholder" @focus="toggle = true" @blur="toggle = false" />
    <div v-show="toggle" class="list-group-flush">
      <button type="button" class="list-group-item list-group-item-action" 
              v-for="item in items" 
              @mousedown="$refs.input.value = item">
        {{ item }}
      </button>
    </div>
  </div>
</template>

这个方案最简单,不需要额外的逻辑修改,适合快速解决问题。

方案二:给blur事件添加延迟执行

通过setTimeout让toggle = false的操作延迟一小段时间,给click事件留足执行时间:

<script>
export default {
  name: 'ListCompletion',
  data() {
    return {
      placeholder: "Gamertag",
      items: ['1', '2', '3', '4'],
      toggle: false
    }
  },
  methods: {
    handleBlur() {
      // 延迟100ms执行隐藏,足够click事件完成赋值
      setTimeout(() => {
        this.toggle = false;
      }, 100);
    }
  }
};
</script>
<template>
  <div class="Container">
    <input ref="input" type="text" :placeholder="placeholder" @focus="toggle = true" @blur="handleBlur" />
    <div v-show="toggle" class="list-group-flush">
      <button type="button" class="list-group-item list-group-item-action" 
              v-for="item in items" 
              @click="$refs.input.value = item">
        {{ item }}
      </button>
    </div>
  </div>
</template>

这种方案保留了click事件的语义,延迟时间可以根据实际情况调整(一般100ms足够)。

方案三:判断blur时的焦点目标(最优雅的方案)

通过event.relatedTarget判断input失去焦点后,焦点是否落在列表容器内——如果是,就不隐藏列表;否则再执行隐藏操作。这种方案更精准,没有延迟:

<script>
export default {
  name: 'ListCompletion',
  data() {
    return {
      placeholder: "Gamertag",
      items: ['1', '2', '3', '4'],
      toggle: false
    }
  },
  methods: {
    handleBlur(event) {
      // 检查失去焦点后,新的焦点元素是否在列表容器内
      const isFocusingList = this.$refs.listContainer?.contains(event.relatedTarget);
      if (!isFocusingList) {
        this.toggle = false;
      }
    }
  }
};
</script>
<template>
  <div class="Container">
    <input ref="input" type="text" :placeholder="placeholder" @focus="toggle = true" @blur="handleBlur" />
    <div v-show="toggle" class="list-group-flush" ref="listContainer">
      <button type="button" class="list-group-item list-group-item-action" 
              v-for="item in items" 
              @click="$refs.input.value = item">
        {{ item }}
      </button>
    </div>
  </div>
</template>

这里给列表容器添加了ref="listContainer",然后在handleBlur中判断新焦点是否属于该容器,避免误隐藏。

推荐优先使用方案三,它的逻辑更严谨,用户体验也更好;如果追求快速实现,方案一最省事。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 18:42:46