refactor(SearchBar): 替换 NutUI Input 为原生 input 元素
重构 SearchBar 组件,移除对 NutUI Input 组件的依赖,改用原生 input 元素实现搜索输入框。这提高了组件的渲染性能并减少了包体积。同时,自定义了搜索图标和清除按钮的样式与交互逻辑,以获得更精细的 UI 控制。
Showing
1 changed file
with
83 additions
and
19 deletions
| 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> | ... | ... |
-
Please register or login to post a comment