Files
shop-toy/src/components/common/SearchBar.vue
FlowerWater 0eb8ac9181 页面提交
2025-11-29 17:20:17 +08:00

138 lines
2.6 KiB
Vue

<template>
<view class="search-bar" :class="{ focused: isFocused }">
<view class="search-input-wrapper">
<text class="icon i-carbon-search"></text>
<input
v-model="searchValue"
class="search-input"
type="text"
:placeholder="placeholder"
:placeholder-style="placeholderStyle"
@focus="handleFocus"
@blur="handleBlur"
@confirm="handleSearch"
>
<text v-if="searchValue" class="icon i-carbon-close" @click="handleClear"></text>
</view>
<view v-if="showCancel && isFocused" class="cancel-btn" @click="handleCancel">
取消
</view>
</view>
</template>
<script setup lang="ts">
interface Props {
modelValue?: string // 搜索值
placeholder?: string // 占位符
showCancel?: boolean // 是否显示取消按钮
}
const props = withDefaults(defineProps<Props>(), {
modelValue: '',
placeholder: '搜索商品',
showCancel: true,
})
const emit = defineEmits<{
'update:modelValue': [value: string]
'search': [value: string]
'cancel': []
'clear': []
}>()
const searchValue = ref(props.modelValue)
const isFocused = ref(false)
const placeholderStyle = 'color: #999; font-size: 28rpx'
// 监听 modelValue 变化
watch(() => props.modelValue, (val) => {
searchValue.value = val
})
// 监听 searchValue 变化
watch(searchValue, (val) => {
emit('update:modelValue', val)
})
function handleFocus() {
isFocused.value = true
}
function handleBlur() {
setTimeout(() => {
isFocused.value = false
}, 200)
}
function handleSearch() {
emit('search', searchValue.value)
}
function handleClear() {
searchValue.value = ''
emit('clear')
}
function handleCancel() {
searchValue.value = ''
isFocused.value = false
emit('cancel')
}
</script>
<style lang="scss" scoped>
.search-bar {
display: flex;
align-items: center;
padding: 16rpx 24rpx;
background: #fff;
transition: all 0.3s;
&.focused {
.search-input-wrapper {
flex: 1;
}
}
}
.search-input-wrapper {
flex: 1;
display: flex;
align-items: center;
height: 64rpx;
padding: 0 24rpx;
background: #f5f5f5;
border-radius: 32rpx;
transition: all 0.3s;
.icon {
font-size: 32rpx;
color: #999;
&.i-carbon-close {
margin-left: auto;
padding: 8rpx;
}
}
.search-input {
flex: 1;
height: 100%;
margin-left: 16rpx;
font-size: 28rpx;
border: none;
outline: none;
background: transparent;
}
}
.cancel-btn {
margin-left: 16rpx;
padding: 0 16rpx;
font-size: 28rpx;
color: #333;
white-space: nowrap;
}
</style>