hookehuyr

refactor(SearchBar): 替换 NutUI Input 为原生 input 元素

重构 SearchBar 组件,移除对 NutUI Input 组件的依赖,改用原生 input 元素实现搜索输入框。这提高了组件的渲染性能并减少了包体积。同时,自定义了搜索图标和清除按钮的样式与交互逻辑,以获得更精细的 UI 控制。
1 <template> 1 <template>
2 <view class="search-bar" :class="containerClass"> 2 <view class="search-bar" :class="containerClass">
3 - <!-- NutUI Input 组件 --> 3 + <view class="search-input-wrapper">
4 - <nut-input 4 + <!-- 左侧搜索图标 -->
5 - v-model="internalValue" 5 + <IconFont
6 + name="search"
7 + :size="iconSize"
8 + :color="iconColor"
9 + class="search-icon"
10 + />
11 +
12 + <!-- 原生输入框 -->
13 + <input
14 + :value="internalValue"
6 :type="inputType" 15 :type="inputType"
7 :placeholder="placeholder" 16 :placeholder="placeholder"
8 :disabled="disabled" 17 :disabled="disabled"
9 confirm-type="search" 18 confirm-type="search"
10 - :clearable="showClear"
11 - :border="false"
12 class="search-input" 19 class="search-input"
13 - @clear="handleClear" 20 + @input="handleInput"
14 - @blur="handleBlur"
15 @focus="handleFocus" 21 @focus="handleFocus"
22 + @blur="handleBlur"
16 @confirm="handleSearch" 23 @confirm="handleSearch"
17 - style="background: transparent;" 24 + />
25 +
26 + <!-- 清除按钮 -->
27 + <view
28 + v-if="showClear && internalValue"
29 + class="clear-icon"
30 + @tap="handleClear"
18 > 31 >
19 - <template #left>
20 <IconFont 32 <IconFont
21 - name="search" 33 + name="close"
22 - :size="iconSize" 34 + :size="14"
23 - :color="iconColor" 35 + color="#9CA3AF"
24 - class="mr-[8rpx]"
25 /> 36 />
26 - </template> 37 + </view>
27 - </nut-input> 38 + </view>
28 </view> 39 </view>
29 </template> 40 </template>
30 41
...@@ -230,26 +241,75 @@ function handleClear() { ...@@ -230,26 +241,75 @@ function handleClear() {
230 emit('clear') 241 emit('clear')
231 emit('update:modelValue', '') 242 emit('update:modelValue', '')
232 } 243 }
244 +
245 +/**
246 + * 处理输入事件(原生 input)
247 + */
248 +function handleInput(e) {
249 + const value = e.detail.value
250 + internalValue.value = value
251 + emit('update:modelValue', value)
252 + emit('input', value)
253 +}
233 </script> 254 </script>
234 255
235 <style lang="less"> 256 <style lang="less">
236 .search-bar { 257 .search-bar {
237 padding: 0; 258 padding: 0;
238 - background: white; 259 + background: transparent;
239 box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); 260 box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
240 border-radius: 44rpx; 261 border-radius: 44rpx;
241 border: 1px solid #e5e7eb; 262 border: 1px solid #e5e7eb;
242 263
243 - :deep(.nut-input) { 264 + .search-input-wrapper {
265 + display: flex;
266 + align-items: center;
244 padding: 24rpx 32rpx; 267 padding: 24rpx 32rpx;
245 - background-color: transparent; 268 + background: transparent;
269 + border-radius: 44rpx;
270 +
271 + .search-icon {
272 + flex-shrink: 0;
273 + margin-right: 16rpx;
274 + }
275 +
276 + .search-input {
277 + flex: 1;
278 + height: 100%;
279 + font-size: 28rpx;
280 + color: #333;
281 + background: transparent;
282 + border: none;
283 + outline: none;
284 + padding: 0;
285 + margin: 0;
286 +
287 + &::placeholder {
288 + color: #9CA3AF;
289 + }
290 +
291 + &:disabled {
292 + color: #ccc;
293 + }
294 + }
295 +
296 + .clear-icon {
297 + flex-shrink: 0;
298 + margin-left: 16rpx;
299 + padding: 8rpx;
300 + cursor: pointer;
301 +
302 + &:active {
303 + opacity: 0.6;
304 + }
305 + }
246 } 306 }
247 307
248 &.search-bar-rounded { 308 &.search-bar-rounded {
249 border-radius: 44rpx; 309 border-radius: 44rpx;
250 overflow: hidden; 310 overflow: hidden;
251 311
252 - :deep(.nut-input) { 312 + .search-input-wrapper {
253 border-radius: 44rpx; 313 border-radius: 44rpx;
254 } 314 }
255 } 315 }
...@@ -261,5 +321,9 @@ function handleClear() { ...@@ -261,5 +321,9 @@ function handleClear() {
261 321
262 .search-bar-rounded { 322 .search-bar-rounded {
263 height: 88rpx; 323 height: 88rpx;
324 +
325 + .search-input-wrapper {
326 + height: 100%;
327 + }
264 } 328 }
265 </style> 329 </style>
......