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

Vue3组合式API搜索组件问题修复求助

问题修复方案

问题1:点击输入框先显示结果再加载

原因:原代码中loading.value = true被包裹在防抖函数内部,导致加载状态要延迟600ms才会触发,此时旧的搜索结果会先渲染出来。

修复代码(父组件):

<script setup>
import { ref } from 'vue'
import Search from './Search.vue'
const elements = ref([])
const loading = ref(false)

function debounce (fn, delay) {
  var timeoutID = null
  return function () {
    clearTimeout(timeoutID)
    var args = arguments
    var that = this
    timeoutID = setTimeout(function () {
      fn.apply(that, args)
    }, delay)
  }
}

// 防抖仅包裹请求逻辑,loading状态立即设置
const search = debounce( (searchValue = '') => {
  fetch(`https://dummyjson.com/products/search?q=${searchValue}`)
    .then(res => res.json())
    .then((data) => {
      elements.value = data.products
    })
    .finally(() => {
      loading.value = false
    });
}, 600)

// 触发搜索时立即设置loading
const handleSearchUpdate = (value) => {
  loading.value = true
  search(value)
}

</script>

<template>
  <Search 
    :loading="loading" 
    @on-update="handleSearchUpdate"
    :items="elements"
  />
</template>

问题2:点击结果项后输入框未填入值

原因:input的blur事件优先级高于li的click事件,点击下拉项时,下拉框会先因blur关闭,导致click事件无法执行。

修复代码(Search.vue):

<script setup>
import { ref, toRefs } from 'vue';
const props = defineProps(['items', 'loading'])
const {items, loading} = toRefs(props)
const inputValue = ref('')
const isOpen = ref(false)

const emit = defineEmits(['on-update'])
const updateValue = (event) => {
  isOpen.value = true
  emit('on-update', event.target.value)
};

// 点击下拉项时设置输入值并关闭下拉框
const selectItem = (itemTitle) => {
  inputValue.value = itemTitle
  isOpen.value = false
}

const onFocus = () => {
  isOpen.value = true;
  emit('on-update', '')
}

// 延迟执行blur逻辑,确保点击事件先完成
const onBlur = () => {
  setTimeout(() => {
    isOpen.value = false
  }, 100)
}

</script>

<template>
  <div>
    <div>
      <input 
        @focus="onFocus" 
        @blur="onBlur"
        @input="updateValue" 
        v-model="inputValue"
      />
      <button @click="inputValue = '';isOpen = false">clear</button>
    </div>
    <div>
      <!-- 仅在下拉框展开时显示内容容器 -->
      <div v-if="isOpen">
        <span v-if="loading">Loading...</span>
        <ul v-else-if="items.length">
          <li 
            style="background-color: red" 
            @mousedown="selectItem(item.title)" <!-- 用mousedown替代click,优先级高于blur -->
            v-for="item in items" 
            :key="item.id"
          >
            {{ item.title}}
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

修复说明

  1. 加载状态问题:将loading.value = true移到防抖函数外部,触发搜索时立即显示加载状态,避免旧结果提前渲染。
  2. 点击填值问题:用mousedown事件替代click(mousedown在blur之前触发),同时给blur事件添加延迟,确保点击事件有足够时间执行,完成输入值的设置和下拉框关闭。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 17:49:51