hookehuyr

refactor(components): 重构 SearchBar 组件并更新搜索页面

- 将 SearchBar 组件从原生 input 重构为 NutUI Input 实现,简化样式和逻辑
- 更新 components.d.ts 类型声明,移除未使用的 NutConfigProvider,修正 PlanPopup 导入路径
- 重构搜索页面,使用 NutTabs 实现分类切换,支持长列表测试数据
- 为搜索结果项添加动画效果,优化用户体验
...@@ -16,7 +16,6 @@ declare module 'vue' { ...@@ -16,7 +16,6 @@ declare module 'vue' {
16 NavHeader: typeof import('./src/components/NavHeader.vue')['default'] 16 NavHeader: typeof import('./src/components/NavHeader.vue')['default']
17 NutAvatar: typeof import('@nutui/nutui-taro')['Avatar'] 17 NutAvatar: typeof import('@nutui/nutui-taro')['Avatar']
18 NutButton: typeof import('@nutui/nutui-taro')['Button'] 18 NutButton: typeof import('@nutui/nutui-taro')['Button']
19 - NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider']
20 NutInput: typeof import('@nutui/nutui-taro')['Input'] 19 NutInput: typeof import('@nutui/nutui-taro')['Input']
21 NutPicker: typeof import('@nutui/nutui-taro')['Picker'] 20 NutPicker: typeof import('@nutui/nutui-taro')['Picker']
22 NutPopup: typeof import('@nutui/nutui-taro')['Popup'] 21 NutPopup: typeof import('@nutui/nutui-taro')['Popup']
...@@ -28,7 +27,7 @@ declare module 'vue' { ...@@ -28,7 +27,7 @@ declare module 'vue' {
28 OfficeViewer: typeof import('./src/components/OfficeViewer.vue')['default'] 27 OfficeViewer: typeof import('./src/components/OfficeViewer.vue')['default']
29 PdfPreview: typeof import('./src/components/PdfPreview.vue')['default'] 28 PdfPreview: typeof import('./src/components/PdfPreview.vue')['default']
30 Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] 29 Picker: typeof import('./src/components/time-picker-data/picker.vue')['default']
31 - PlanPopup: typeof import('./src/components/PlanSchemes/PlanPopup.vue')['default'] 30 + PlanPopup: typeof import('./src/components/PlanPopup/index.vue')['default']
32 PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] 31 PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default']
33 QrCode: typeof import('./src/components/qrCode.vue')['default'] 32 QrCode: typeof import('./src/components/qrCode.vue')['default']
34 QrCodeSearch: typeof import('./src/components/qrCodeSearch.vue')['default'] 33 QrCodeSearch: typeof import('./src/components/qrCodeSearch.vue')['default']
......
1 <template> 1 <template>
2 - <view 2 + <view class="search-bar" :class="containerClass">
3 - class="search-bar flex items-center" 3 + <!-- NutUI Input 组件 -->
4 - :class="containerClass" 4 + <nut-input
5 - >
6 - <!-- Search Icon -->
7 - <IconFont
8 - name="search"
9 - :size="iconSize"
10 - :color="iconColor"
11 - class="flex-shrink-0 mr-[16rpx]"
12 - />
13 -
14 - <!-- Input -->
15 - <input
16 v-model="internalValue" 5 v-model="internalValue"
17 :type="inputType" 6 :type="inputType"
18 :placeholder="placeholder" 7 :placeholder="placeholder"
19 - :placeholder-class="placeholderClass"
20 - :class="inputClass"
21 :disabled="disabled" 8 :disabled="disabled"
22 - @focus="handleFocus" 9 + confirm-type="search"
10 + :clearable="showClear"
11 + class="search-input"
12 + @clear="handleClear"
23 @blur="handleBlur" 13 @blur="handleBlur"
24 - @input="handleInput" 14 + @focus="handleFocus"
25 @confirm="handleSearch" 15 @confirm="handleSearch"
26 - /> 16 + >
27 - 17 + <template #left>
28 - <!-- Clear Button --> 18 + <IconFont
29 - <IconFont 19 + name="search"
30 - v-if="showClear && internalValue" 20 + :size="iconSize"
31 - name="close" 21 + :color="iconColor"
32 - :size="clearIconSize" 22 + class="mr-[8rpx]"
33 - :color="clearIconColor" 23 + />
34 - class="flex-shrink-0 ml-[16rpx]" 24 + </template>
35 - @tap="handleClear" 25 + </nut-input>
36 - />
37 </view> 26 </view>
38 </template> 27 </template>
39 28
...@@ -42,9 +31,9 @@ import { ref, watch, computed } from 'vue' ...@@ -42,9 +31,9 @@ import { ref, watch, computed } from 'vue'
42 import IconFont from '@/components/IconFont.vue' 31 import IconFont from '@/components/IconFont.vue'
43 32
44 /** 33 /**
45 - * SearchBar 组件 34 + * SearchBar 组件(基于 NutUI Input)
46 * 35 *
47 - * @description 可复用的搜索栏组件,支持多种样式变体 36 + * @description 可复用的搜索栏组件,使用 NutUI Input 组件实现
48 * @author Claude Code 37 * @author Claude Code
49 * @example 38 * @example
50 * <SearchBar 39 * <SearchBar
...@@ -136,24 +125,6 @@ const props = defineProps({ ...@@ -136,24 +125,6 @@ const props = defineProps({
136 iconColor: { 125 iconColor: {
137 type: String, 126 type: String,
138 default: '#9CA3AF' 127 default: '#9CA3AF'
139 - },
140 - /**
141 - * 清除图标大小
142 - * @type {number|string}
143 - * @default 16
144 - */
145 - clearIconSize: {
146 - type: [Number, String],
147 - default: 16
148 - },
149 - /**
150 - * 清除图标颜色
151 - * @type {string}
152 - * @default '#9CA3AF'
153 - */
154 - clearIconColor: {
155 - type: String,
156 - default: '#9CA3AF'
157 } 128 }
158 }) 129 })
159 130
...@@ -198,41 +169,17 @@ const internalValue = ref(props.modelValue) ...@@ -198,41 +169,17 @@ const internalValue = ref(props.modelValue)
198 169
199 // 容器样式类 170 // 容器样式类
200 const containerClass = computed(() => { 171 const containerClass = computed(() => {
201 - const base = [ 172 + const classes = ['search-bar']
202 - 'bg-white',
203 - 'shadow-sm',
204 - 'px-[40rpx]', // 左右 padding
205 - props.variant === 'rounded' ? 'rounded-full' : 'rounded-[20rpx]'
206 - ]
207 -
208 - if (props.showBorder) {
209 - base.push('border', 'border-gray-200')
210 - } else {
211 - base.push('border', 'border-gray-50')
212 - }
213 173
214 - // 高度样式
215 if (props.variant === 'rounded') { 174 if (props.variant === 'rounded') {
216 - base.push('h-[88rpx]') 175 + classes.push('search-bar-rounded')
217 - } else {
218 - base.push('py-[24rpx]')
219 } 176 }
220 177
221 - return base.join(' ') 178 + if (props.showBorder) {
222 -}) 179 + classes.push('search-bar-bordered')
223 - 180 + }
224 -// 占位符样式类
225 -const placeholderClass = 'text-gray-400 text-[28rpx]'
226 181
227 -// 输入框样式类 182 + return classes.join(' ')
228 -const inputClass = computed(() => {
229 - return [
230 - 'flex-1',
231 - 'text-[28rpx]',
232 - 'bg-transparent',
233 - 'outline-none',
234 - props.disabled ? 'opacity-50' : ''
235 - ].filter(Boolean).join(' ')
236 }) 183 })
237 184
238 // 监听 modelValue 变化 185 // 监听 modelValue 变化
...@@ -243,12 +190,14 @@ watch(() => props.modelValue, (newValue) => { ...@@ -243,12 +190,14 @@ watch(() => props.modelValue, (newValue) => {
243 // 监听内部值变化,触发更新 190 // 监听内部值变化,触发更新
244 watch(internalValue, (newValue) => { 191 watch(internalValue, (newValue) => {
245 emit('update:modelValue', newValue) 192 emit('update:modelValue', newValue)
193 + emit('input', newValue)
246 }) 194 })
247 195
248 /** 196 /**
249 * 处理获得焦点 197 * 处理获得焦点
250 */ 198 */
251 function handleFocus() { 199 function handleFocus() {
200 + console.log('[SearchBar Component] 获得焦点')
252 emit('focus') 201 emit('focus')
253 } 202 }
254 203
...@@ -256,27 +205,25 @@ function handleFocus() { ...@@ -256,27 +205,25 @@ function handleFocus() {
256 * 处理失去焦点 205 * 处理失去焦点
257 */ 206 */
258 function handleBlur() { 207 function handleBlur() {
208 + console.log('[SearchBar Component] 失去焦点')
259 emit('blur') 209 emit('blur')
260 } 210 }
261 211
262 /** 212 /**
263 - * 处理输入
264 - */
265 -function handleInput(e) {
266 - emit('input', internalValue.value)
267 -}
268 -
269 -/**
270 * 处理搜索(回车) 213 * 处理搜索(回车)
271 */ 214 */
272 function handleSearch() { 215 function handleSearch() {
216 + console.log('[SearchBar Component] handleSearch 被调用')
217 + console.log('[SearchBar Component] 当前输入值:', internalValue.value)
273 emit('search', internalValue.value) 218 emit('search', internalValue.value)
219 + console.log('[SearchBar Component] search 事件已发送')
274 } 220 }
275 221
276 /** 222 /**
277 * 清除输入 223 * 清除输入
278 */ 224 */
279 function handleClear() { 225 function handleClear() {
226 + console.log('[SearchBar Component] 清除输入')
280 internalValue.value = '' 227 internalValue.value = ''
281 emit('clear') 228 emit('clear')
282 emit('update:modelValue', '') 229 emit('update:modelValue', '')
...@@ -284,5 +231,30 @@ function handleClear() { ...@@ -284,5 +231,30 @@ function handleClear() {
284 </script> 231 </script>
285 232
286 <style lang="less" scoped> 233 <style lang="less" scoped>
287 -/* 样式通过 TailwindCSS 类控制 */ 234 +.search-bar {
235 + padding: 0;
236 + background: white;
237 + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
238 +
239 + :deep(.nut-input) {
240 + padding: 24rpx 32rpx;
241 + background-color: transparent;
242 + }
243 +
244 + &.search-bar-rounded {
245 + border-radius: 9999rpx;
246 +
247 + :deep(.nut-input) {
248 + border-radius: 9999rpx;
249 + }
250 + }
251 +
252 + &.search-bar-bordered {
253 + border: 1px solid #e5e7eb;
254 + }
255 +}
256 +
257 +.search-bar-rounded {
258 + height: 88rpx;
259 +}
288 </style> 260 </style>
......
This diff is collapsed. Click to expand it.