refactor: (4) enhance MarketSearchBar with internal query handling and debouncing
- Introduced an internal query state to improve UI responsiveness during search input. - Implemented a debounced search function to optimize performance and reduce unnecessary emissions. - Updated conditions for displaying keyboard hints and clear button based on the new internal query. - Ensured both internal and actual search queries are cleared appropriately. These changes enhance the user experience by providing immediate feedback while typing and optimizing search operations.
This commit is contained in:
parent
1f321dce4a
commit
b3428c2905
1 changed files with 31 additions and 13 deletions
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<Input
|
||||
ref="searchInputRef"
|
||||
:model-value="searchQuery"
|
||||
:model-value="internalQuery || searchQuery"
|
||||
@update:model-value="handleSearchChange"
|
||||
@keydown="handleKeydown"
|
||||
@focus="handleFocus"
|
||||
|
|
@ -21,13 +21,13 @@
|
|||
<!-- Enhanced Features (keyboard hints, clear button) -->
|
||||
<div class="absolute inset-y-0 right-0 pr-3 flex items-center gap-2">
|
||||
<!-- Keyboard Shortcuts Hint (only for enhanced mode on desktop) -->
|
||||
<div v-if="showEnhancements && showKeyboardHints && !searchQuery && isDesktop" class="text-xs text-muted-foreground flex items-center gap-1">
|
||||
<div v-if="showEnhancements && showKeyboardHints && !internalQuery && !searchQuery && isDesktop" class="text-xs text-muted-foreground flex items-center gap-1">
|
||||
<Badge variant="outline" class="px-1 py-0 text-xs">⌘ K</Badge>
|
||||
</div>
|
||||
|
||||
<!-- Clear Button -->
|
||||
<Button
|
||||
v-if="searchQuery"
|
||||
v-if="internalQuery || searchQuery"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@click="handleClear"
|
||||
|
|
@ -89,7 +89,7 @@ import { Input } from '@/components/ui/input'
|
|||
import { Button } from '@/components/ui/button'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Search, X } from 'lucide-vue-next'
|
||||
import { useLocalStorage, useBreakpoints, breakpointsTailwind } from '@vueuse/core'
|
||||
import { useLocalStorage, useBreakpoints, breakpointsTailwind, useDebounceFn } from '@vueuse/core'
|
||||
import type { Product } from '../types/market'
|
||||
|
||||
// Conditional imports for enhanced mode
|
||||
|
|
@ -265,20 +265,35 @@ const searchSuggestions = computed(() => {
|
|||
})
|
||||
|
||||
// Methods
|
||||
const handleSearchChange = (value: string | number) => {
|
||||
const stringValue = String(value)
|
||||
setSearchQuery(stringValue)
|
||||
emit('update:modelValue', stringValue)
|
||||
emit('search', stringValue)
|
||||
// Internal search query for immediate UI updates
|
||||
const internalQuery = ref('')
|
||||
|
||||
// Debounced search function for performance optimization
|
||||
const debouncedSearch = useDebounceFn((value: string) => {
|
||||
setSearchQuery(value)
|
||||
emit('search', value)
|
||||
emit('results', filteredItems.value)
|
||||
|
||||
// Add to recent searches when user finishes typing (enhanced mode only)
|
||||
if (props.showEnhancements && stringValue.trim() && stringValue.length >= 3) {
|
||||
addToRecentSearches(stringValue.trim())
|
||||
if (props.showEnhancements && value.trim() && value.length >= 3) {
|
||||
addToRecentSearches(value.trim())
|
||||
}
|
||||
}, 300)
|
||||
|
||||
const handleSearchChange = (value: string | number) => {
|
||||
const stringValue = String(value)
|
||||
|
||||
// Update internal query immediately for responsive UI
|
||||
internalQuery.value = stringValue
|
||||
emit('update:modelValue', stringValue)
|
||||
|
||||
// Debounce the actual search computation
|
||||
debouncedSearch(stringValue)
|
||||
}
|
||||
|
||||
const handleClear = () => {
|
||||
// Clear both internal and actual search queries
|
||||
internalQuery.value = ''
|
||||
clearSearch()
|
||||
emit('update:modelValue', '')
|
||||
emit('search', '')
|
||||
|
|
@ -297,7 +312,7 @@ const handleKeydown = (event: KeyboardEvent) => {
|
|||
// Handle basic Escape key for simple mode
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault()
|
||||
if (searchQuery.value) {
|
||||
if (internalQuery.value || searchQuery.value) {
|
||||
handleClear()
|
||||
}
|
||||
return
|
||||
|
|
@ -307,7 +322,7 @@ const handleKeydown = (event: KeyboardEvent) => {
|
|||
if (useSearchKeyboardShortcuts.value && handleSearchKeydown) {
|
||||
const shouldClear = handleSearchKeydown(event)
|
||||
if (shouldClear) {
|
||||
if (searchQuery.value) {
|
||||
if (internalQuery.value || searchQuery.value) {
|
||||
handleClear()
|
||||
} else {
|
||||
blurSearchInput()
|
||||
|
|
@ -318,15 +333,18 @@ const handleKeydown = (event: KeyboardEvent) => {
|
|||
|
||||
const filterByCategory = (category: string) => {
|
||||
emit('filter-category', category)
|
||||
internalQuery.value = category
|
||||
setSearchQuery(category)
|
||||
}
|
||||
|
||||
const applySuggestion = (suggestion: string) => {
|
||||
internalQuery.value = suggestion
|
||||
setSearchQuery(suggestion)
|
||||
addToRecentSearches(suggestion)
|
||||
}
|
||||
|
||||
const applyRecentSearch = (recent: string) => {
|
||||
internalQuery.value = recent
|
||||
setSearchQuery(recent)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue