tang-ui-x 1.0.0

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 (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -0
  3. package/components/TActionSheet/index.uvue +170 -0
  4. package/components/TActionSheet/type.uts +29 -0
  5. package/components/TAvatar/index.uvue +156 -0
  6. package/components/TAvatar/type.uts +54 -0
  7. package/components/TBadge/index.uvue +152 -0
  8. package/components/TBadge/type.uts +48 -0
  9. package/components/TButton/README.md +111 -0
  10. package/components/TButton/index.uvue +380 -0
  11. package/components/TButton/type.uts +95 -0
  12. package/components/TCard/index.uvue +174 -0
  13. package/components/TCard/type.uts +50 -0
  14. package/components/TCell/index.uvue +49 -0
  15. package/components/TCheckbox/index.uvue +187 -0
  16. package/components/TCheckboxGroup/index.uvue +139 -0
  17. package/components/TCheckboxGroup/type.uts +26 -0
  18. package/components/TCol/index.uvue +82 -0
  19. package/components/TCol/type.uts +30 -0
  20. package/components/TCollapse/index.uvue +93 -0
  21. package/components/TCollapse/type.uts +36 -0
  22. package/components/TCollapseItem/index.uvue +194 -0
  23. package/components/TCollapseItem/type.uts +25 -0
  24. package/components/TDialog/index.uvue +386 -0
  25. package/components/TDialog/type.uts +84 -0
  26. package/components/TDivider/index.uvue +235 -0
  27. package/components/TDivider/type.uts +91 -0
  28. package/components/TEmpty/index.uvue +128 -0
  29. package/components/TErrorState/index.uvue +57 -0
  30. package/components/TGrid/index.uvue +115 -0
  31. package/components/TGrid/type.uts +77 -0
  32. package/components/TGridItem/index.uvue +243 -0
  33. package/components/TGridItem/type.uts +64 -0
  34. package/components/TIcon/index.uvue +96 -0
  35. package/components/TImage/index.uvue +255 -0
  36. package/components/TImage/type.uts +146 -0
  37. package/components/TInput/README.md +119 -0
  38. package/components/TInput/index.uvue +376 -0
  39. package/components/TInput/type.uts +138 -0
  40. package/components/TList/index.uvue +82 -0
  41. package/components/TList/type.uts +68 -0
  42. package/components/TListItem/index.uvue +161 -0
  43. package/components/TListItem/type.uts +49 -0
  44. package/components/TLoading/index.uvue +153 -0
  45. package/components/TLoading/type.uts +43 -0
  46. package/components/TNavBar/index.uvue +120 -0
  47. package/components/TNavBar/type.uts +22 -0
  48. package/components/TNoticeBar/index.uvue +106 -0
  49. package/components/TNoticeBar/type.uts +21 -0
  50. package/components/TNumberInput/index.uvue +226 -0
  51. package/components/TPicker/index.uvue +276 -0
  52. package/components/TPicker/type.uts +105 -0
  53. package/components/TPopup/index.uvue +442 -0
  54. package/components/TProgress/index.uvue +103 -0
  55. package/components/TProgress/type.uts +64 -0
  56. package/components/TRadioButton/index.uvue +232 -0
  57. package/components/TRadioGroup/index.uvue +117 -0
  58. package/components/TRadioGroup/type.uts +25 -0
  59. package/components/TRate/index.uvue +182 -0
  60. package/components/TRow/index.uvue +105 -0
  61. package/components/TRow/type.uts +52 -0
  62. package/components/TSearchBar/index.uvue +255 -0
  63. package/components/TSearchBar/type.uts +140 -0
  64. package/components/TSelect/index.uvue +655 -0
  65. package/components/TSelect/type.uts +57 -0
  66. package/components/TSlider/index.uvue +72 -0
  67. package/components/TSlider/type.uts +21 -0
  68. package/components/TSwiper/index.uvue +222 -0
  69. package/components/TSwiper/type.uts +77 -0
  70. package/components/TSwitch/index.uvue +177 -0
  71. package/components/TSwitch/type.uts +52 -0
  72. package/components/TText/README.md +124 -0
  73. package/components/TText/index.uvue +257 -0
  74. package/components/TText/type.uts +114 -0
  75. package/components/TTextarea/index.uvue +239 -0
  76. package/components/TTextarea/type.uts +106 -0
  77. package/components/TToast/type.uts +14 -0
  78. package/components/Tabs/README.md +297 -0
  79. package/components/Tabs/index.uvue +383 -0
  80. package/components/Tabs/type.uts +10 -0
  81. package/components/Tags/README.md +297 -0
  82. package/components/Tags/index.uvue +383 -0
  83. package/components/Tags/type.uts +10 -0
  84. package/components/VbenFrom/index.uvue +392 -0
  85. package/composables/useModal.uts +294 -0
  86. package/composables/useTheme.uts +235 -0
  87. package/composables/useToast.uts +322 -0
  88. package/index.js +62 -0
  89. package/package.json +48 -0
  90. package/style/colors/index.scss +157 -0
  91. package/style/index.scss +399 -0
  92. package/types/index.uts +52 -0
  93. package/uni.scss +79 -0
  94. package/utils/color.uts +92 -0
  95. package/utils/common.uts +245 -0
  96. package/utils/dom.uts +275 -0
  97. package/utils/index.uts +10 -0
  98. package/utils/validator.uts +155 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # UniApp X UI 组件库
2
+
3
+ 基于 uni-app x 的移动端 UI 组件库,提供 42+ 个高质量组件。
4
+
5
+ ## ✨ 特性
6
+
7
+ - 🎨 42+ 个精美组件
8
+ - 💪 使用 TypeScript 开发,提供完整的类型定义
9
+ - 📱 专为 uni-app x 优化
10
+ - 🔥 使用 Vue 3 Composition API
11
+ - 🎯 支持 defineModel 双向绑定
12
+ - 📦 支持按需引入
13
+ - 🌈 统一的设计规范
14
+
15
+ ## 📦 安装
16
+
17
+ ```bash
18
+ npm install tang-ui-x
19
+ # 或
20
+ yarn add tang-ui-x
21
+ # 或
22
+ pnpm add tang-ui-x
23
+ ```
24
+
25
+ ## 🔨 使用
26
+
27
+ ### 方式一:easycom 自动导入(推荐)
28
+
29
+ 在 `pages.json` 中配置 easycom:
30
+
31
+ ```json
32
+ {
33
+ "easycom": {
34
+ "autoscan": true,
35
+ "custom": {
36
+ "^T(.*)": "tang-ui-x/components/T$1/T$1.vue"
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ 然后在页面中直接使用:
43
+
44
+ ```vue
45
+ <template>
46
+ <view>
47
+ <TButton type="primary">按钮</TButton>
48
+ <TInput v-model="value" placeholder="请输入" />
49
+ </view>
50
+ </template>
51
+ ```
52
+
53
+ ### 方式二:按需引入
54
+
55
+ ```vue
56
+ <script setup>
57
+ import { TButton, TInput } from 'tang-ui-x'
58
+ </script>
59
+
60
+ <template>
61
+ <view>
62
+ <TButton type="primary">按钮</TButton>
63
+ <TInput v-model="value" placeholder="请输入" />
64
+ </view>
65
+ </template>
66
+ ```
67
+
68
+ ## 📚 组件列表
69
+
70
+ ### 基础组件 (5个)
71
+ - TButton - 按钮
72
+ - TIcon - 图标
73
+ - TText - 文本
74
+ - TImage - 图片
75
+ - TDivider - 分割线
76
+
77
+ ### 布局组件 (8个)
78
+ - TCard - 卡片
79
+ - TList - 列表
80
+ - TListItem - 列表项
81
+ - TCell - 单元格
82
+ - TGrid - 宫格
83
+ - TGridItem - 宫格项
84
+ - TRow - 栅格行
85
+ - TCol - 栅格列
86
+
87
+ ### 表单组件 (13个)
88
+ - TInput - 输入框
89
+ - TNumberInput - 数字输入
90
+ - TTextarea - 多行文本输入
91
+ - TSearchBar - 搜索框
92
+ - TSwitch - 开关
93
+ - TCheckbox - 复选框
94
+ - TCheckboxGroup - 复选组
95
+ - TRadioButton - 单选按钮
96
+ - TRadioGroup - 单选组
97
+ - TSelect - 选择器
98
+ - TSlider - 滑块
99
+ - TRate - 评分
100
+ - TPicker - 选择器
101
+
102
+ ### 数据展示 (9个)
103
+ - Tags - 标签
104
+ - TBadge - 徽标
105
+ - TAvatar - 头像
106
+ - TProgress - 进度条
107
+ - TNoticeBar - 通知栏
108
+ - TCollapse - 折叠面板
109
+ - TCollapseItem - 折叠面板项
110
+ - TEmpty - 空状态
111
+ - TErrorState - 错误状态
112
+ - TSwiper - 轮播图
113
+
114
+ ### 反馈组件 (5个)
115
+ - TLoading - 加载
116
+ - TToast - 轻提示
117
+ - TDialog - 对话框
118
+ - TPopup - 弹出层
119
+ - TActionSheet - 动作面板
120
+
121
+ ### 导航组件 (2个)
122
+ - Tabs - 标签页
123
+ - TNavBar - 导航栏
124
+
125
+ ## 📖 文档
126
+
127
+ 详细文档请访问:[https://github.com/sugar258596/tang-ui](https://github.com/sugar258596/tang-ui)
128
+
129
+ ## 🤝 贡献
130
+
131
+ 欢迎提交 Issue 和 Pull Request!
132
+
133
+ ## � 链接
134
+
135
+ - [GitHub](https://github.com/sugar258596/tang-ui)
136
+ - [Issues](https://github.com/sugar258596/tang-ui/issues)
137
+ - [NPM](https://www.npmjs.com/package/tang-ui-x)
138
+
139
+ ## 📄 License
140
+
141
+ MIT License
@@ -0,0 +1,170 @@
1
+ <script setup lang="uts">
2
+ import TPopup from '@/components/TPopup/index.uvue'
3
+ import type { ActionSheetAction, TActionSheetProps } from './type.uts'
4
+
5
+ /**
6
+ * TActionSheet 动作面板组件
7
+ * @description 底部弹出的动作菜单,基于 TPopup 组件实现
8
+ */
9
+
10
+ // Props 定义 (从 type.uts 导入,排除 show)
11
+ type Props = Omit<TActionSheetProps, 'show'>
12
+
13
+ const props = withDefaults(defineProps<Props>(), {
14
+ actions: () => [] as ActionSheetAction[],
15
+ title: '',
16
+ description: '',
17
+ cancelText: '取消',
18
+ closeOnClickAction: true,
19
+ closeOnClickOverlay: true,
20
+ customClass: '',
21
+ customStyle: ''
22
+ })
23
+
24
+ // 使用 defineModel 管理显示状态 (v-model)
25
+ const visible = defineModel<boolean>({ default: false })
26
+
27
+ const emit = defineEmits<{
28
+ select: [action: ActionSheetAction, index: number]
29
+ cancel: []
30
+ close: []
31
+ }>()
32
+
33
+ const handleSelect = (action: ActionSheetAction, index: number): void => {
34
+ if (action.disabled || action.loading) return
35
+
36
+ emit('select', action, index)
37
+ if (props.closeOnClickAction) {
38
+ visible.value = false
39
+ }
40
+ }
41
+
42
+ const handleCancel = (): void => {
43
+ emit('cancel')
44
+ visible.value = false
45
+ }
46
+
47
+ const handleClose = (): void => {
48
+ emit('close')
49
+ }
50
+ </script>
51
+
52
+ <template>
53
+ <TPopup
54
+ v-model="visible"
55
+ position="bottom"
56
+ :show-title="false"
57
+ :show-close="false"
58
+ :close-on-click-overlay="closeOnClickOverlay"
59
+ :border-radius="16"
60
+ height="auto"
61
+ @close="handleClose"
62
+ >
63
+ <view class="t-action-sheet" :class="customClass" :style="customStyle">
64
+ <!-- 头部:标题和描述 -->
65
+ <view v-if="title || description" class="t-action-sheet__header">
66
+ <text v-if="title" class="t-action-sheet__title">{{ title }}</text>
67
+ <text v-if="description" class="t-action-sheet__description">{{ description }}</text>
68
+ </view>
69
+
70
+ <!-- 操作列表 -->
71
+ <view class="t-action-sheet__actions">
72
+ <view
73
+ v-for="(action, index) in actions"
74
+ :key="index"
75
+ class="t-action-sheet__action"
76
+ :class="{
77
+ 't-action-sheet__action--disabled': action.disabled,
78
+ 't-action-sheet__action--loading': action.loading
79
+ }"
80
+ @click="() => handleSelect(action, index)"
81
+ >
82
+ <text
83
+ class="t-action-sheet__action-text"
84
+ :style="action.color ? `color: ${action.color}` : ''"
85
+ >
86
+ {{ action.name }}
87
+ </text>
88
+ </view>
89
+ </view>
90
+
91
+ <!-- 取消按钮 -->
92
+ <view class="t-action-sheet__cancel" @click="handleCancel">
93
+ <text class="t-action-sheet__cancel-text">{{ cancelText }}</text>
94
+ </view>
95
+ </view>
96
+ </TPopup>
97
+ </template>
98
+
99
+ <style lang="scss" scoped>
100
+ .t-action-sheet {
101
+ background-color: transparent;
102
+ padding: 0;
103
+ }
104
+
105
+ .t-action-sheet__header {
106
+ padding: 16px;
107
+ text-align: center;
108
+ border-bottom: 1px solid #ebedf0;
109
+ }
110
+
111
+ .t-action-sheet__title {
112
+ font-size: 16px;
113
+ font-weight: 500;
114
+ color: #323233;
115
+ display: block;
116
+ margin-bottom: 8px;
117
+ }
118
+
119
+ .t-action-sheet__description {
120
+ font-size: 14px;
121
+ color: #969799;
122
+ display: block;
123
+ }
124
+
125
+ .t-action-sheet__actions {
126
+ max-height: 400px;
127
+ overflow-y: auto;
128
+ }
129
+
130
+ .t-action-sheet__action {
131
+ padding: 16px;
132
+ display: flex;;
133
+ align-items: center;
134
+ text-align: center;
135
+ border-bottom: 1px solid #ebedf0;
136
+ cursor: pointer;
137
+
138
+ &:active {
139
+ background-color: #f5f5f5;
140
+ }
141
+
142
+ &--disabled {
143
+ opacity: 0.5;
144
+ cursor: not-allowed;
145
+ }
146
+ }
147
+
148
+ .t-action-sheet__action-text {
149
+ font-size: 16px;
150
+ color: #323233;
151
+ }
152
+
153
+ .t-action-sheet__cancel {
154
+ padding: 16px;
155
+ display: flex;;
156
+ align-items: center;
157
+ text-align: center;
158
+ border-top: 8px solid #f5f5f5;
159
+ cursor: pointer;
160
+
161
+ &:active {
162
+ background-color: #f5f5f5;
163
+ }
164
+ }
165
+
166
+ .t-action-sheet__cancel-text {
167
+ font-size: 16px;
168
+ color: #323233;
169
+ }
170
+ </style>
@@ -0,0 +1,29 @@
1
+ /**
2
+ * TActionSheet 组件类型定义
3
+ */
4
+
5
+ export interface ActionSheetAction {
6
+ name: string
7
+ color?: string
8
+ disabled?: boolean
9
+ loading?: boolean
10
+ }
11
+
12
+ export interface TActionSheetProps {
13
+ show?: boolean
14
+ actions?: ActionSheetAction[]
15
+ title?: string
16
+ description?: string
17
+ cancelText?: string
18
+ closeOnClickAction?: boolean
19
+ closeOnClickOverlay?: boolean
20
+ customClass?: string
21
+ customStyle?: string
22
+ }
23
+
24
+ export interface TActionSheetEmits {
25
+ 'update:show': (value: boolean) => void
26
+ select: (action: ActionSheetAction, index: number) => void
27
+ cancel: () => void
28
+ close: () => void
29
+ }
@@ -0,0 +1,156 @@
1
+ <script setup lang="uts" >
2
+ import { computed, ref } from 'vue'
3
+ import type { TAvatarProps } from './type.uts'
4
+
5
+ /**
6
+ * TAvatar 头像组件
7
+ * @description 用于展示用户头像或图标
8
+ */
9
+
10
+ // 定义 props
11
+ const props = withDefaults(defineProps<TAvatarProps>(), {
12
+ src: '',
13
+ size: 'medium',
14
+ shape: 'circle',
15
+ alt: '',
16
+ bgColor: '#c0c4cc',
17
+ color: '#ffffff',
18
+ fit: 'cover'
19
+ })
20
+
21
+ // 定义 emits
22
+ const emit = defineEmits<{
23
+ click: []
24
+ error: []
25
+ }>()
26
+
27
+ // 图片加载失败标记
28
+ const hasLoadError = ref<boolean>(false)
29
+
30
+ /**
31
+ * 计算头像大小
32
+ */
33
+ const avatarSize = computed<number>(() => {
34
+ if (typeof props.size === 'number') {
35
+ return props.size
36
+ }
37
+
38
+ const sizeMap = {
39
+ small: 32,
40
+ medium: 40,
41
+ large: 56
42
+ }
43
+
44
+ return sizeMap[props.size] || 40
45
+ })
46
+
47
+ /**
48
+ * 计算头像样式类
49
+ */
50
+ const avatarClass = computed<string>(() => {
51
+ const classes: string[] = ['t-avatar']
52
+
53
+ classes.push(`t-avatar--${props.shape}`)
54
+
55
+ return classes.join(' ')
56
+ })
57
+
58
+ /**
59
+ * 计算头像样式
60
+ */
61
+ const avatarStyle = computed<string>(() => {
62
+ const styles: string[] = []
63
+
64
+ const size = avatarSize.value
65
+ styles.push(`width: ${size}px`)
66
+ styles.push(`height: ${size}px`)
67
+
68
+ if (!props.src || hasLoadError.value) {
69
+ styles.push(`background-color: ${props.bgColor}`)
70
+ }
71
+
72
+ return styles.join('; ')
73
+ })
74
+
75
+ /**
76
+ * 计算文字样式
77
+ */
78
+ const textStyle = computed<string>(() => {
79
+ const styles: string[] = []
80
+
81
+ styles.push(`color: ${props.color}`)
82
+ styles.push(`font-size: ${avatarSize.value / 2}px`)
83
+
84
+ return styles.join('; ')
85
+ })
86
+
87
+ /**
88
+ * 处理点击事件
89
+ */
90
+ const handleClick = (): void => {
91
+ emit('click')
92
+ }
93
+
94
+ /**
95
+ * 处理图片加载失败
96
+ */
97
+ const handleError = (): void => {
98
+ hasLoadError.value = true
99
+ emit('error')
100
+ }
101
+
102
+ /**
103
+ * 获取显示的文字(取首字符)
104
+ */
105
+ const displayText = computed<string>(() => {
106
+ if (props.alt) {
107
+ return props.alt.charAt(0).toUpperCase()
108
+ }
109
+ return ''
110
+ })
111
+ </script>
112
+
113
+ <template>
114
+ <view :class="avatarClass" :style="avatarStyle" @click="handleClick">
115
+ <image
116
+ v-if="src && !hasLoadError"
117
+ class="t-avatar__image"
118
+ :src="src"
119
+ :mode="fit"
120
+ @error="handleError"
121
+ />
122
+ <text v-else-if="alt" class="t-avatar__text" :style="textStyle">
123
+ {{ displayText }}
124
+ </text>
125
+ <slot v-else></slot>
126
+ </view>
127
+ </template>
128
+
129
+ <style lang="scss" scoped>
130
+ .t-avatar {
131
+ display: inline-flex;
132
+ align-items: center;
133
+ justify-content: center;
134
+ overflow: hidden;
135
+ position: relative;
136
+ cursor: pointer;
137
+
138
+ &--circle {
139
+ border-radius: 50%;
140
+ }
141
+
142
+ &--square {
143
+ border-radius: 4px;
144
+ }
145
+
146
+ &__image {
147
+ width: 100%;
148
+ height: 100%;
149
+ }
150
+
151
+ &__text {
152
+ font-weight: 500;
153
+ text-align: center;
154
+ }
155
+ }
156
+ </style>
@@ -0,0 +1,54 @@
1
+ /**
2
+ * TAvatar 头像组件属性类型定义
3
+ */
4
+ export type TAvatarProps = {
5
+ /**
6
+ * 头像图片地址
7
+ */
8
+ src?: string
9
+
10
+ /**
11
+ * 头像大小
12
+ * @default "medium"
13
+ */
14
+ size?: 'small' | 'medium' | 'large' | number
15
+
16
+ /**
17
+ * 头像形状
18
+ * @default "circle"
19
+ */
20
+ shape?: 'circle' | 'square'
21
+
22
+ /**
23
+ * 替代文字(无图片时显示)
24
+ */
25
+ alt?: string
26
+
27
+ /**
28
+ * 背景色
29
+ */
30
+ bgColor?: string
31
+
32
+ /**
33
+ * 文字颜色
34
+ */
35
+ color?: string
36
+
37
+ /**
38
+ * 图片填充模式
39
+ * @default "cover"
40
+ */
41
+ fit?: 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'
42
+ }
43
+
44
+ export type TAvatarEmits = {
45
+ /**
46
+ * 点击头像时触发
47
+ */
48
+ click: () => void
49
+
50
+ /**
51
+ * 图片加载失败时触发
52
+ */
53
+ error: () => void
54
+ }
@@ -0,0 +1,152 @@
1
+ <script setup lang="uts" >
2
+ import { computed } from 'vue'
3
+ import type { TBadgeProps } from './type.uts'
4
+
5
+ /**
6
+ * TBadge 徽标组件
7
+ * @description 用于显示数字或状态标记
8
+ */
9
+
10
+ // 定义 props
11
+ const props = withDefaults(defineProps<TBadgeProps>(), {
12
+ value: '',
13
+ max: 99,
14
+ isDot: false,
15
+ hidden: false,
16
+ type: 'danger',
17
+ bgColor: '',
18
+ color: '',
19
+ offset: () => [0, 0] as [number, number]
20
+ })
21
+
22
+ /**
23
+ * 计算显示的内容
24
+ */
25
+ const displayValue = computed<string>(() => {
26
+ if (props.isDot) {
27
+ return ''
28
+ }
29
+
30
+ const val = props.value
31
+ if (typeof val === 'number' && val > props.max) {
32
+ return `${props.max}+`
33
+ }
34
+
35
+ return String(val)
36
+ })
37
+
38
+ /**
39
+ * 计算徽标样式类
40
+ */
41
+ const badgeClass = computed<string>(() => {
42
+ const classes: string[] = ['t-badge__content']
43
+
44
+ if (props.isDot) {
45
+ classes.push('t-badge__content--dot')
46
+ }
47
+
48
+ classes.push(`t-badge__content--${props.type}`)
49
+
50
+ return classes.join(' ')
51
+ })
52
+
53
+ /**
54
+ * 计算徽标样式
55
+ */
56
+ const badgeStyle = computed<string>(() => {
57
+ const styles: string[] = []
58
+
59
+ if (props.bgColor != '') {
60
+ styles.push(`background-color: ${props.bgColor}`)
61
+ }
62
+
63
+ if (props.color != '') {
64
+ styles.push(`color: ${props.color}`)
65
+ }
66
+
67
+ if (props.offset && props.offset.length === 2) {
68
+ const [x, y] = props.offset
69
+ if (x !== 0) {
70
+ styles.push(`right: ${-x}px`)
71
+ }
72
+ if (y !== 0) {
73
+ styles.push(`top: ${y}px`)
74
+ }
75
+ }
76
+
77
+ return styles.join('; ')
78
+ })
79
+
80
+ /**
81
+ * 是否显示徽标
82
+ */
83
+ const showBadge = computed<boolean>(() => {
84
+ return !props.hidden && (props.isDot || props.value !== '' && props.value !== 0)
85
+ })
86
+ </script>
87
+
88
+ <template>
89
+ <view class="t-badge">
90
+ <slot></slot>
91
+ <view v-if="showBadge" :class="badgeClass" :style="badgeStyle">
92
+ <text v-if="!isDot" class="t-badge__text">{{ displayValue }}</text>
93
+ </view>
94
+ </view>
95
+ </template>
96
+
97
+ <style lang="scss" scoped>
98
+ .t-badge {
99
+ position: relative;
100
+ display: inline-block;
101
+ overflow:visible;
102
+
103
+ &__content {
104
+ position: absolute;
105
+ top: 0;
106
+ right: 0;
107
+ transform: translate(50%, -50%);
108
+ border-radius: 10px;
109
+ padding: 2px 6px;
110
+ font-size: 12px;
111
+ line-height: 1.2;
112
+ white-space: nowrap;
113
+ z-index: 1;
114
+
115
+ &--dot {
116
+ width: 8px;
117
+ height: 8px;
118
+ padding: 0;
119
+ border-radius: 50%;
120
+ }
121
+
122
+ &--primary {
123
+ background-color: #409eff;
124
+ color: #ffffff;
125
+ }
126
+
127
+ &--success {
128
+ background-color: #67c23a;
129
+ color: #ffffff;
130
+ }
131
+
132
+ &--warning {
133
+ background-color: #e6a23c;
134
+ color: #ffffff;
135
+ }
136
+
137
+ &--danger {
138
+ background-color: #f56c6c;
139
+ color: #ffffff;
140
+ }
141
+
142
+ &--info {
143
+ background-color: #909399;
144
+ color: #ffffff;
145
+ }
146
+ }
147
+
148
+ &__text {
149
+ font-size: 12px;
150
+ }
151
+ }
152
+ </style>