im-ui-mobile 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/components/im-avatar/im-avatar.vue +7 -7
  2. package/components/im-badge/im-badge.vue +326 -0
  3. package/components/im-button/im-button.vue +71 -34
  4. package/components/im-card/im-card.vue +563 -0
  5. package/components/im-chat-item/im-chat-item.vue +5 -4
  6. package/components/im-col/im-col.vue +191 -0
  7. package/components/im-dialog/im-dialog.vue +543 -0
  8. package/components/im-double-tap-view/im-double-tap-view.vue +93 -0
  9. package/components/im-emoji-picker/im-emoji-picker.vue +1143 -0
  10. package/components/im-friend-item/im-friend-item.vue +1 -1
  11. package/components/im-group-item/im-group-item.vue +1 -1
  12. package/components/im-group-member-selector/im-group-member-selector.vue +5 -5
  13. package/components/im-group-rtc-join/im-group-rtc-join.vue +8 -8
  14. package/components/im-icon/im-icon.vue +593 -0
  15. package/components/im-image-upload/im-image-upload.vue +0 -2
  16. package/components/im-link/im-link.vue +628 -0
  17. package/components/im-loading/im-loading.vue +13 -4
  18. package/components/im-mention-picker/im-mention-picker.vue +8 -7
  19. package/components/im-message-action/im-message-action.vue +678 -0
  20. package/components/im-message-item/im-message-item.vue +28 -26
  21. package/components/im-message-list/im-message-list.vue +1108 -0
  22. package/components/im-modal/im-modal.vue +373 -0
  23. package/components/im-nav-bar/im-nav-bar.vue +689 -75
  24. package/components/im-parse/im-parse.vue +1054 -0
  25. package/components/im-popup/im-popup.vue +467 -0
  26. package/components/im-read-receipt/im-read-receipt.vue +10 -10
  27. package/components/im-row/im-row.vue +189 -0
  28. package/components/im-search/im-search.vue +762 -0
  29. package/components/im-sku/im-sku.vue +720 -0
  30. package/components/im-sku/utils/helper.ts +182 -0
  31. package/components/im-stepper/im-stepper.vue +585 -0
  32. package/components/im-stepper/utils/helper.ts +167 -0
  33. package/components/im-tabs/im-tabs.vue +1022 -0
  34. package/components/im-tabs/tabs-navigation.vue +489 -0
  35. package/components/im-tabs/utils/helper.ts +181 -0
  36. package/components/im-tabs-tab-pane/im-tabs-tab-pane.vue +145 -0
  37. package/components/im-upload/im-upload.vue +1236 -0
  38. package/components/im-voice-input/im-voice-input.vue +1 -1
  39. package/index.js +3 -5
  40. package/index.scss +19 -0
  41. package/libs/emoji-data.ts +229 -0
  42. package/libs/index.ts +16 -16
  43. package/package.json +1 -2
  44. package/styles/button.scss +33 -33
  45. package/theme.scss +2 -2
  46. package/types/components/badge.d.ts +42 -0
  47. package/types/components/button.d.ts +2 -1
  48. package/types/components/card.d.ts +122 -0
  49. package/types/components/col.d.ts +37 -0
  50. package/types/components/dialog.d.ts +125 -0
  51. package/types/components/double-tap-view.d.ts +31 -0
  52. package/types/components/emoji-picker.d.ts +121 -0
  53. package/types/components/group-rtc-join.d.ts +1 -1
  54. package/types/components/icon.d.ts +77 -0
  55. package/types/components/link.d.ts +55 -0
  56. package/types/components/loading.d.ts +1 -0
  57. package/types/components/message-action.d.ts +96 -0
  58. package/types/components/message-item.d.ts +2 -2
  59. package/types/components/message-list.d.ts +136 -0
  60. package/types/components/modal.d.ts +106 -0
  61. package/types/components/nav-bar.d.ts +125 -0
  62. package/types/components/parse.d.ts +90 -0
  63. package/types/components/popup.d.ts +58 -0
  64. package/types/components/row.d.ts +31 -0
  65. package/types/components/search.d.ts +54 -0
  66. package/types/components/sku.d.ts +195 -0
  67. package/types/components/stepper.d.ts +99 -0
  68. package/types/components/tabs-tab-pane.d.ts +27 -0
  69. package/types/components/tabs.d.ts +117 -0
  70. package/types/components/upload.d.ts +137 -0
  71. package/types/components.d.ts +19 -1
  72. package/types/index.d.ts +38 -1
  73. package/types/libs/index.d.ts +10 -10
  74. package/types/utils/base64.d.ts +5 -0
  75. package/types/utils/dom.d.ts +3 -0
  76. package/types/utils/enums.d.ts +4 -5
  77. package/types/utils/validator.d.ts +74 -0
  78. package/utils/base64.js +18 -0
  79. package/utils/dom.js +353 -1
  80. package/utils/enums.js +4 -5
  81. package/utils/validator.js +230 -0
  82. package/components/im-file-upload/im-file-upload.vue +0 -309
  83. package/plugins/uview-plus.js +0 -29
  84. package/types/components/arrow-bar.d.ts +0 -14
  85. package/types/components/file-upload.d.ts +0 -58
@@ -1,99 +1,713 @@
1
1
  <template>
2
- <view class="nav-bar">
3
- <!-- #ifdef APP-PLUS -->
4
- <view style="height: var(--status-bar-height)"></view>
5
- <!-- #endif -->
6
- <view class="nav-bar-content">
7
- <!-- #ifndef MP-WEIXIN -->
8
- <view class="back" @click="handleBackClick" v-if="back">
9
- <u-icon name="arrow-left" :size="iconFontSize"></u-icon>
2
+ <view class="im-nav-bar" :class="[
3
+ `im-nav-bar--${type}`,
4
+ `im-nav-bar--${theme}`,
5
+ {
6
+ 'im-nav-bar--fixed': fixed,
7
+ 'im-nav-bar--border': border,
8
+ 'im-nav-bar--transparent': transparent,
9
+ 'im-nav-bar--shadow': shadow,
10
+ 'im-nav-bar--immersive': immersive
11
+ }
12
+ ]" :style="navStyle">
13
+ <!-- 状态栏占位(沉浸式导航栏) -->
14
+ <view v-if="immersive" class="im-nav-bar__status-bar" :style="statusBarStyle"></view>
15
+
16
+ <!-- 导航栏主体 -->
17
+ <view class="im-nav-bar__content" :style="contentStyle">
18
+ <!-- 左区域 -->
19
+ <view class="im-nav-bar__left">
20
+ <!-- 返回按钮(优先显示返回按钮) -->
21
+ <view v-if="showBack && showLeft" class="im-nav-bar__back" @click="handleBack">
22
+ <im-icon v-if="backIcon" :name="backIcon" :size="backIconSize" :color="backIconColor" />
23
+ <text v-if="backText" class="im-nav-bar__back-text">{{ backText }}</text>
24
+ </view>
25
+
26
+ <!-- 自定义左侧内容 -->
27
+ <slot v-else-if="$slots.left" name="left"></slot>
28
+
29
+ <!-- 左侧图标或文字 -->
30
+ <view v-else-if="leftIcon || leftText" class="im-nav-bar__left-custom" @click="handleLeftClick">
31
+ <im-icon v-if="leftIcon" :name="leftIcon" :size="iconSize" :color="iconColor" />
32
+ <text v-if="leftText" class="im-nav-bar__left-text">{{ leftText }}</text>
33
+ </view>
34
+ </view>
35
+
36
+ <!-- 标题区域 -->
37
+ <view class="im-nav-bar__title" :style="titleStyle" @click="handleTitleClick">
38
+ <!-- 自定义标题内容 -->
39
+ <slot v-if="$slots.title" name="title"></slot>
40
+
41
+ <!-- 默认标题 -->
42
+ <template v-else>
43
+ <im-icon v-if="titleIcon" :name="titleIcon" :size="titleIconSize" :color="titleIconColor"
44
+ class="im-nav-bar__title-icon" />
45
+ <text v-if="title" class="im-nav-bar__title-text" :class="{ 'im-nav-bar__title-text--ellipsis': titleEllipsis }">
46
+ {{ title }}
47
+ </text>
48
+ <slot v-else></slot>
49
+ <im-icon v-if="titleRightIcon" :name="titleRightIcon" :size="titleRightIconSize"
50
+ :color="titleRightIconColor" class="im-nav-bar__title-right-icon" />
51
+ </template>
10
52
  </view>
11
- <!-- #endif -->
12
- <view class="title" v-if="title">
13
- <slot></slot>
53
+
54
+ <!-- 右区域 -->
55
+ <view class="im-nav-bar__right">
56
+ <!-- 自定义右侧内容 -->
57
+ <slot v-if="$slots.right" name="right"></slot>
58
+
59
+ <!-- 右侧图标或文字 -->
60
+ <view v-else-if="rightIcon || rightText" class="im-nav-bar__right-custom" @click="handleRightClick">
61
+ <text v-if="rightText" class="im-nav-bar__right-text">{{ rightText }}</text>
62
+ <im-icon v-if="rightIcon" :name="rightIcon" :size="iconSize" :color="iconColor" />
63
+ </view>
64
+
65
+ <!-- 右侧多个操作按钮 -->
66
+ <view v-if="actions && actions.length > 0" class="im-nav-bar__actions">
67
+ <view v-for="(action, index) in actions" :key="index" class="im-nav-bar__action"
68
+ @click="handleActionClick(action, index)">
69
+ <im-icon v-if="action.icon" :name="action.icon" :size="action.iconSize || iconSize"
70
+ :color="action.iconColor || iconColor" :type="action.iconType" />
71
+ <text v-if="action.text" class="im-nav-bar__action-text" :style="{ color: action.textColor }">
72
+ {{ action.text }}
73
+ </text>
74
+ </view>
75
+ </view>
14
76
  </view>
15
- <view class="btn">
16
- <u-icon class="btn-item" v-if="search" name="search" :size="iconFontSize"
17
- @click="$emit('search')"></u-icon>
18
- <u-icon class="btn-item" v-if="add" name="plus" :size="iconFontSize" @click="$emit('add')"></u-icon>
19
- <u-icon class="btn-item" v-if="more" name="more-dot-fill" :size="iconFontSize"
20
- @click="$emit('more')"></u-icon>
77
+ </view>
78
+
79
+ <!-- 搜索栏模式 -->
80
+ <view v-if="type === 'search'" class="im-nav-bar__search" :style="searchStyle">
81
+ <view class="im-nav-bar__search-box">
82
+ <im-icon name="search" :size="20" color="#999" class="im-nav-bar__search-icon" />
83
+ <input class="im-nav-bar__search-input" :value="searchValue" :placeholder="placeholder"
84
+ :placeholder-style="placeholderStyle" :focus="searchFocus" :disabled="searchDisabled"
85
+ @input="handleSearchInput" @focus="handleSearchFocus" @blur="handleSearchBlur"
86
+ @confirm="handleSearchConfirm" />
87
+ <view v-if="searchValue" class="im-nav-bar__search-clear" @click="handleSearchClear">
88
+ <im-icon name="close" :size="16" color="#999" />
89
+ </view>
21
90
  </view>
91
+ <text v-if="showSearchButton" class="im-nav-bar__search-button" @click="handleSearchButton">
92
+ {{ searchButtonText }}
93
+ </text>
22
94
  </view>
23
95
  </view>
24
96
  </template>
25
97
 
26
98
  <script setup lang="ts">
99
+ import { ref, computed, onMounted, watch } from 'vue'
100
+ import { onLoad, onShow } from '@dcloudio/uni-app'
101
+ import type { IconType } from '../../types/components/icon'
102
+
103
+ // 类型定义
104
+ interface NavBarAction {
105
+ text?: string
106
+ icon?: string
107
+ iconSize?: string | number
108
+ iconColor?: string
109
+ iconType?: IconType
110
+ textColor?: string
111
+ disabled?: boolean
112
+ badge?: string | number
113
+ data?: any,
114
+ click?: Function | undefined
115
+ }
116
+
27
117
  interface Props {
28
- back?: boolean;
29
- title?: boolean;
30
- search?: boolean;
31
- add?: boolean;
32
- more?: boolean;
33
- iconFontSize?: number;
118
+ // 基础属性
119
+ title?: string
120
+ type?: 'default' | 'search' | 'home' | 'custom'
121
+ theme?: 'light' | 'dark' | 'primary' | 'transparent'
122
+ fixed?: boolean
123
+ border?: boolean
124
+ transparent?: boolean
125
+ shadow?: boolean
126
+ immersive?: boolean // 沉浸式(占位状态栏)
127
+ safeArea?: boolean // 适配刘海屏安全区域
128
+
129
+ // 标题相关
130
+ titleIcon?: string
131
+ titleIconSize?: string | number
132
+ titleIconColor?: string
133
+ titleRightIcon?: string
134
+ titleRightIconSize?: string | number
135
+ titleRightIconColor?: string
136
+ titleEllipsis?: boolean
137
+ titleStyle?: Record<string, any>
138
+
139
+ // 返回按钮
140
+ showBack?: boolean
141
+ backIcon?: string
142
+ backIconSize?: string | number
143
+ backIconColor?: string
144
+ backText?: string
145
+ delta?: number // 返回的页面数
146
+
147
+ // 左侧区域
148
+ showLeft?: boolean
149
+ leftIcon?: string
150
+ leftText?: string
151
+
152
+ // 右侧区域
153
+ rightIcon?: string
154
+ rightText?: string
155
+ actions?: NavBarAction[]
156
+
157
+ // 图标通用
158
+ iconSize?: string | number
159
+ iconColor?: string
160
+
161
+ // 搜索栏模式
162
+ searchValue?: string
163
+ placeholder?: string
164
+ placeholderStyle?: string
165
+ searchFocus?: boolean
166
+ searchDisabled?: boolean
167
+ showSearchButton?: boolean
168
+ searchButtonText?: string
169
+
170
+ // 样式控制
171
+ height?: string | number
172
+ backgroundColor?: string
173
+ color?: string
174
+ statusBarColor?: string
175
+ zIndex?: number
176
+
177
+ // 自定义样式
178
+ customStyle?: Record<string, any>
34
179
  }
35
180
 
36
181
  const props = withDefaults(defineProps<Props>(), {
37
- back: false,
38
- title: true,
39
- search: false,
40
- add: false,
41
- more: false,
42
- iconFontSize: 24
43
- });
44
-
45
- const handleBackClick = () => {
46
- uni.navigateBack({
47
- delta: 1
48
- });
49
- };
182
+ title: '',
183
+ type: 'default',
184
+ theme: 'light',
185
+ fixed: true,
186
+ border: true,
187
+ shadow: true,
188
+ immersive: false,
189
+ safeArea: true,
190
+ titleIconSize: 18,
191
+ titleIconColor: 'inherit',
192
+ titleRightIconSize: 18,
193
+ titleRightIconColor: 'inherit',
194
+ titleEllipsis: true,
195
+ showBack: true,
196
+ showLeft: true,
197
+ backIcon: 'arrow-left',
198
+ backIconSize: 32,
199
+ backIconColor: 'inherit',
200
+ delta: 1,
201
+ iconSize: 32,
202
+ iconColor: 'inherit',
203
+ placeholder: '请输入搜索内容',
204
+ searchButtonText: '搜索',
205
+ searchFocus: false,
206
+ searchDisabled: false,
207
+ showSearchButton: false,
208
+ height: '88rpx',
209
+ backgroundColor: '',
210
+ color: '',
211
+ zIndex: 1000
212
+ })
213
+
214
+ const emit = defineEmits<{
215
+ // 基础事件
216
+ 'back': [event: MouseEvent]
217
+ 'left-click': [event: MouseEvent]
218
+ 'right-click': [event: MouseEvent]
219
+ 'title-click': [event: MouseEvent]
220
+
221
+ // 搜索事件
222
+ 'search-input': [value: string, event: any]
223
+ 'search-focus': [event: any]
224
+ 'search-blur': [event: any]
225
+ 'search-confirm': [value: string, event: any]
226
+ 'search-clear': []
227
+ 'search-button-click': [value: string]
228
+
229
+ // 操作事件
230
+ 'action-click': [action: NavBarAction, index: number]
231
+
232
+ // 生命周期
233
+ 'init': []
234
+ 'ready': []
235
+ }>()
236
+
237
+ // 响应式数据
238
+ const searchValue = ref(props.searchValue || '')
239
+ const statusBarHeight = ref(0)
240
+ const safeAreaBottom = ref(0)
241
+ const isIPhoneX = ref(false)
242
+
243
+ // 计算样式
244
+ const navStyle = computed(() => {
245
+ const style: Record<string, any> = {
246
+ zIndex: props.zIndex
247
+ }
248
+
249
+ if (props.fixed) {
250
+ style.position = 'fixed'
251
+ style.top = '0'
252
+ style.left = '0'
253
+ style.right = '0'
254
+ }
255
+
256
+ if (props.backgroundColor) {
257
+ style.backgroundColor = props.backgroundColor
258
+ }
259
+
260
+ if (props.customStyle) {
261
+ Object.assign(style, props.customStyle)
262
+ }
263
+
264
+ return style
265
+ })
266
+
267
+ const statusBarStyle = computed(() => {
268
+ const style: Record<string, any> = {
269
+ height: `${statusBarHeight.value}px`
270
+ }
271
+
272
+ if (props.statusBarColor) {
273
+ style.backgroundColor = props.statusBarColor
274
+ } else if (props.backgroundColor) {
275
+ style.backgroundColor = props.backgroundColor
276
+ }
277
+
278
+ return style
279
+ })
280
+
281
+ const contentStyle = computed(() => {
282
+ const style: Record<string, any> = {
283
+ height: typeof props.height === 'number' ? `${props.height}px` : props.height
284
+ }
285
+
286
+ if (props.immersive) {
287
+ style.paddingTop = `${statusBarHeight.value}px`
288
+ }
289
+
290
+ if (props.safeArea && isIPhoneX.value) {
291
+ style.paddingBottom = `${safeAreaBottom.value}px`
292
+ }
293
+
294
+ return style
295
+ })
296
+
297
+ const searchStyle = computed(() => {
298
+ const style: Record<string, any> = {}
299
+
300
+ if (props.backgroundColor) {
301
+ style.backgroundColor = props.backgroundColor
302
+ }
303
+
304
+ return style
305
+ })
306
+
307
+ // 获取系统信息
308
+ const getSystemInfo = () => {
309
+ uni.getSystemInfo({
310
+ success: (res) => {
311
+ // 状态栏高度
312
+ statusBarHeight.value = res.statusBarHeight || 0
313
+
314
+ // 判断是否为 iPhone X 及以上机型
315
+ const model = res.model?.toLowerCase() || ''
316
+ isIPhoneX.value = /iphone x|iphone 1[0-9]|iphone [1-9][0-9]/.test(model)
317
+
318
+ // 安全区域底部高度(针对刘海屏)
319
+ if (isIPhoneX.value) {
320
+ safeAreaBottom.value = res.safeAreaInsets?.bottom || 34
321
+ }
322
+ }
323
+ })
324
+ }
325
+
326
+ // 事件处理
327
+ const handleBack = (event: MouseEvent) => {
328
+ if (props.delta > 0) {
329
+ uni.navigateBack({
330
+ delta: props.delta,
331
+ fail: () => {
332
+ // 返回失败时触发事件
333
+ emit('back', event)
334
+ }
335
+ })
336
+ } else {
337
+ emit('back', event)
338
+ }
339
+ }
340
+
341
+ const handleLeftClick = (event: MouseEvent) => {
342
+ emit('left-click', event)
343
+ }
344
+
345
+ const handleRightClick = (event: MouseEvent) => {
346
+ emit('right-click', event)
347
+ }
348
+
349
+ const handleTitleClick = (event: MouseEvent) => {
350
+ emit('title-click', event)
351
+ }
352
+
353
+ const handleActionClick = (action: NavBarAction, index: number) => {
354
+ if (!action.disabled) {
355
+ if (action.click) {
356
+ action.click({ action, index })
357
+ }
358
+ emit('action-click', action, index)
359
+ }
360
+ }
361
+
362
+ // 搜索相关事件
363
+ const handleSearchInput = (event: any) => {
364
+ searchValue.value = event.detail?.value || ''
365
+ emit('search-input', searchValue.value, event)
366
+ }
367
+
368
+ const handleSearchFocus = (event: any) => {
369
+ emit('search-focus', event)
370
+ }
371
+
372
+ const handleSearchBlur = (event: any) => {
373
+ emit('search-blur', event)
374
+ }
375
+
376
+ const handleSearchConfirm = (event: any) => {
377
+ emit('search-confirm', searchValue.value, event)
378
+ }
379
+
380
+ const handleSearchClear = () => {
381
+ searchValue.value = ''
382
+ emit('search-clear')
383
+ emit('search-input', '', null)
384
+ }
385
+
386
+ const handleSearchButton = () => {
387
+ emit('search-button-click', searchValue.value)
388
+ }
389
+
390
+ // 监听搜索值变化
391
+ watch(() => props.searchValue, (newVal) => {
392
+ if (newVal !== undefined) {
393
+ searchValue.value = newVal
394
+ }
395
+ })
396
+
397
+ // 生命周期
398
+ onMounted(() => {
399
+ getSystemInfo()
400
+ emit('init')
401
+ })
402
+
403
+ onLoad(() => {
404
+ getSystemInfo()
405
+ })
406
+
407
+ onShow(() => {
408
+ emit('ready')
409
+ })
410
+
411
+ // 暴露给父组件的方法
412
+ defineExpose({
413
+ focusSearch: () => {
414
+ // 聚焦搜索框的方法
415
+ },
416
+ blurSearch: () => {
417
+ // 失焦搜索框的方法
418
+ },
419
+ clearSearch: () => {
420
+ searchValue.value = ''
421
+ emit('search-clear')
422
+ },
423
+ getSearchValue: () => searchValue.value,
424
+ setSearchValue: (value: string) => {
425
+ searchValue.value = value
426
+ }
427
+ })
50
428
  </script>
51
429
 
52
430
  <style scoped lang="scss">
53
- .nav-bar {
54
- background: $im-bg-linear;
55
- position: fixed;
56
- top: 0;
431
+ .im-nav-bar {
57
432
  width: 100%;
58
- color: $im-text-color;
59
- border-bottom: 1px solid $im-border-light;
60
- font-size: $im-font-size-large;
61
- z-index: 99;
62
-
63
- .nav-bar-content {
64
- display: flex;
65
- align-items: center;
66
- justify-content: center;
67
- box-sizing: border-box;
68
- height: $im-nav-bar-height;
69
-
70
- .title {}
71
-
72
- .back {
73
- position: absolute;
74
- left: 0;
75
- height: 100%;
76
- display: flex;
77
- align-items: center;
78
- padding: 12px;
79
- font-size: 22px;
80
- box-sizing: border-box;
433
+ box-sizing: border-box;
434
+ font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
435
+
436
+ // 主题变体
437
+ &--light {
438
+ background-color: #ffffff;
439
+ color: #333333;
440
+
441
+ .im-nav-bar__content {
442
+ border-bottom-color: #f0f0f0;
81
443
  }
444
+ }
82
445
 
83
- .btn {
84
- position: absolute;
85
- right: 0;
86
- height: 100%;
87
- display: flex;
88
- padding: 12px;
89
- align-items: center;
90
- box-sizing: border-box;
91
-
92
- .btn-item {
93
- margin-left: 8px;
94
- }
446
+ &--dark {
447
+ background-color: #333333;
448
+ color: #ffffff;
449
+
450
+ .im-nav-bar__content {
451
+ border-bottom-color: rgba(255, 255, 255, 0.1);
452
+ }
453
+ }
454
+
455
+ &--primary {
456
+ background-color: var(--color-primary, #409EFF);
457
+ color: #ffffff;
458
+
459
+ .im-nav-bar__content {
460
+ border-bottom-color: rgba(255, 255, 255, 0.2);
461
+ }
462
+ }
463
+
464
+ &--transparent {
465
+ background-color: transparent;
466
+ color: #ffffff;
467
+
468
+ &.im-nav-bar--border .im-nav-bar__content {
469
+ border-bottom-color: rgba(255, 255, 255, 0.1);
470
+ }
471
+ }
472
+
473
+ // 固定定位
474
+ &--fixed {
475
+ position: fixed;
476
+ top: 0;
477
+ left: 0;
478
+ right: 0;
479
+ z-index: 1000;
480
+ }
481
+
482
+ // 边框
483
+ &--border {
484
+ .im-nav-bar__content {
485
+ border-bottom-width: 1rpx;
486
+ border-bottom-style: solid;
487
+ }
488
+ }
489
+
490
+ // 阴影
491
+ &--shadow {
492
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
493
+ }
494
+
495
+ // 沉浸式
496
+ &--immersive {
497
+ .im-nav-bar__status-bar {
498
+ width: 100%;
499
+ }
500
+ }
501
+ }
502
+
503
+ // 状态栏
504
+ .im-nav-bar__status-bar {
505
+ width: 100%;
506
+ background-color: inherit;
507
+ }
508
+
509
+ // 导航栏内容
510
+ .im-nav-bar__content {
511
+ display: flex;
512
+ align-items: center;
513
+ justify-content: space-between;
514
+ // padding: 0 32rpx;
515
+ box-sizing: border-box;
516
+ height: 88rpx;
517
+ }
518
+
519
+ // 左侧区域
520
+ .im-nav-bar__left {
521
+ flex-shrink: 0;
522
+ display: flex;
523
+ align-items: center;
524
+ min-width: 120rpx;
525
+ }
526
+
527
+ .im-nav-bar__back {
528
+ display: flex;
529
+ align-items: center;
530
+ padding: 16rpx 0;
531
+ cursor: pointer;
532
+
533
+ &-text {
534
+ margin-left: 8rpx;
535
+ font-size: 28rpx;
536
+ }
537
+ }
538
+
539
+ .im-nav-bar__left-custom {
540
+ display: flex;
541
+ align-items: center;
542
+ padding: 16rpx 0;
543
+ cursor: pointer;
544
+
545
+ &-text {
546
+ margin-left: 8rpx;
547
+ font-size: 28rpx;
548
+ }
549
+ }
550
+
551
+ // 标题区域
552
+ .im-nav-bar__title {
553
+ flex: 1;
554
+ display: flex;
555
+ align-items: center;
556
+ justify-content: center;
557
+ font-size: 32rpx;
558
+ font-weight: 600;
559
+ text-align: center;
560
+ padding: 0 20rpx;
561
+ cursor: pointer;
562
+ overflow: hidden;
563
+ }
564
+
565
+ .im-nav-bar__title-text {
566
+ &--ellipsis {
567
+ white-space: nowrap;
568
+ overflow: hidden;
569
+ text-overflow: ellipsis;
570
+ }
571
+ }
572
+
573
+ .im-nav-bar__title-icon {
574
+ margin-right: 8rpx;
575
+ flex-shrink: 0;
576
+ }
577
+
578
+ .im-nav-bar__title-right-icon {
579
+ margin-left: 8rpx;
580
+ flex-shrink: 0;
581
+ }
582
+
583
+ // 右侧区域
584
+ .im-nav-bar__right {
585
+ flex-shrink: 0;
586
+ display: flex;
587
+ align-items: center;
588
+ justify-content: flex-end;
589
+ min-width: 120rpx;
590
+ }
591
+
592
+ .im-nav-bar__right-custom {
593
+ display: flex;
594
+ align-items: center;
595
+ padding: 16rpx 0;
596
+ cursor: pointer;
597
+
598
+ &-text {
599
+ margin-right: 8rpx;
600
+ font-size: 28rpx;
601
+ }
602
+ }
603
+
604
+ .im-nav-bar__actions {
605
+ display: flex;
606
+ align-items: center;
607
+ gap: 24rpx;
608
+ }
609
+
610
+ .im-nav-bar__action {
611
+ display: flex;
612
+ align-items: center;
613
+ padding: 16rpx 0;
614
+ cursor: pointer;
615
+ position: relative;
616
+
617
+ &-text {
618
+ font-size: 28rpx;
619
+ margin-left: 4rpx;
620
+ }
621
+
622
+ // 角标
623
+ &:has(.im-badge) {
624
+ position: relative;
625
+ }
626
+ }
627
+
628
+ // 搜索栏模式
629
+ .im-nav-bar__search {
630
+ padding: 16rpx 32rpx;
631
+ background-color: inherit;
632
+ }
633
+
634
+ .im-nav-bar__search-box {
635
+ display: flex;
636
+ align-items: center;
637
+ background-color: rgba(255, 255, 255, 0.2);
638
+ border-radius: 32rpx;
639
+ padding: 0 24rpx;
640
+ height: 64rpx;
641
+
642
+ .im-nav-bar--light & {
643
+ background-color: #f5f5f5;
644
+ }
645
+ }
646
+
647
+ .im-nav-bar__search-icon {
648
+ margin-right: 12rpx;
649
+ flex-shrink: 0;
650
+ }
651
+
652
+ .im-nav-bar__search-input {
653
+ flex: 1;
654
+ height: 100%;
655
+ font-size: 28rpx;
656
+ color: inherit;
657
+ background-color: transparent;
658
+
659
+ &::placeholder {
660
+ color: inherit;
661
+ opacity: 0.6;
662
+ }
663
+
664
+ .im-nav-bar--light & {
665
+ color: #333333;
666
+
667
+ &::placeholder {
668
+ color: #999999;
95
669
  }
96
670
  }
671
+ }
672
+
673
+ .im-nav-bar__search-clear {
674
+ margin-left: 12rpx;
675
+ padding: 4rpx;
676
+ border-radius: 50%;
677
+ background-color: rgba(0, 0, 0, 0.1);
678
+ display: flex;
679
+ align-items: center;
680
+ justify-content: center;
681
+ cursor: pointer;
682
+
683
+ .im-nav-bar--light & {
684
+ background-color: rgba(0, 0, 0, 0.05);
685
+ }
686
+ }
687
+
688
+ .im-nav-bar__search-button {
689
+ margin-left: 16rpx;
690
+ font-size: 28rpx;
691
+ font-weight: 500;
692
+ cursor: pointer;
693
+ flex-shrink: 0;
694
+ padding: 8rpx 16rpx;
695
+ }
97
696
 
697
+ // 安全区域适配
698
+ .safe-area-inset-bottom {
699
+ padding-bottom: env(safe-area-inset-bottom);
700
+ padding-bottom: constant(safe-area-inset-bottom);
701
+ }
702
+
703
+ // 响应式调整
704
+ @media (max-width: 768px) {
705
+ .im-nav-bar__content {
706
+ padding: 0 24rpx;
707
+ }
708
+
709
+ .im-nav-bar__search {
710
+ padding: 16rpx 24rpx;
711
+ }
98
712
  }
99
713
  </style>