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>
修复说明
- 加载状态问题:将
loading.value = true移到防抖函数外部,触发搜索时立即显示加载状态,避免旧结果提前渲染。 - 点击填值问题:用
mousedown事件替代click(mousedown在blur之前触发),同时给blur事件添加延迟,确保点击事件有足够时间执行,完成输入值的设置和下拉框关闭。
内容的提问来源于stack exchange,提问作者Asking
相关产品推荐
相关产品推荐

