stellar-ui-plus 1.17.15 → 1.17.17

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.
@@ -13,5 +13,6 @@
13
13
  | `textAlign` | 文字对齐方式 | `string` | `'right'` | - | - |
14
14
  | `textSize` | 文字大小 | `string / number` | `16` | - | - |
15
15
  | `displayTextThreshold` | 显示文本的阈值 | `number` | `0` | - | - |
16
+ | `stageData` | 阶段配置信息,该值存在时percentage将不生效 | `object` | `{}` | - | - |
16
17
 
17
18
 
@@ -8,8 +8,8 @@
8
8
 
9
9
  #### 背景色
10
10
 
11
- - 背景色支持纯色、渐变色、图片
12
- - 支持设置激活部分的背景(`activeBg`)和未激活部分(`inactiveBg`)的背景
11
+ - 背景色支持纯色、渐变色、图片
12
+ - 支持设置激活部分的背景(`activeBg`)和未激活部分(`inactiveBg`)的背景
13
13
 
14
14
  ```html
15
15
  <ste-progress :percentage="40"></ste-progress>
@@ -19,7 +19,7 @@
19
19
 
20
20
  #### 线条粗细
21
21
 
22
- - 通过`strokeWidth`设置线条的粗细
22
+ - 通过`strokeWidth`设置线条的粗细
23
23
 
24
24
  ```html
25
25
  <ste-progress :percentage="40" strokeWidth="20"></ste-progress>
@@ -34,8 +34,8 @@
34
34
 
35
35
  #### 长度
36
36
 
37
- - 通过`width`设置进度条长度
38
- - 默认是`100%`,跟随父容器的宽度
37
+ - 通过`width`设置进度条长度
38
+ - 默认是`100%`,跟随父容器的宽度
39
39
 
40
40
  ```html
41
41
  <ste-progress :percentage="40" width="80%"></ste-progress>
@@ -50,10 +50,10 @@
50
50
 
51
51
  #### 自定义文字内容
52
52
 
53
- - 通过`pivotText`属性来自定义进度条内文字显示的内容
54
- - 通过`textColor`属性来自定义进度条内文字的颜色
55
- - 通过`textAlign`属性来自定义进度条内文字的对齐方式
56
- - 通过`textSize`属性来自定义进度条内文字的大小
53
+ - 通过`pivotText`属性来自定义进度条内文字显示的内容
54
+ - 通过`textColor`属性来自定义进度条内文字的颜色
55
+ - 通过`textAlign`属性来自定义进度条内文字的对齐方式
56
+ - 通过`textSize`属性来自定义进度条内文字的大小
57
57
 
58
58
  ```html
59
59
  <ste-progress :percentage="30" pivotText="已抢30%"></ste-progress>
@@ -64,14 +64,27 @@
64
64
 
65
65
  #### 文本显示阈值
66
66
 
67
- - 当进度条百分比(`percentage`)小于阈值时(`displayTextThreshold`),进度条的内容将不会显示
68
- - 默认阈值是`0`,此时内容将始终显示
67
+ - 当进度条百分比(`percentage`)小于阈值时(`displayTextThreshold`),进度条的内容将不会显示
68
+ - 默认阈值是`0`,此时内容将始终显示
69
69
 
70
70
  ```html
71
71
  <ste-progress :percentage="14" :displayTextThreshold="15"></ste-progress>
72
72
  <ste-progress :percentage="35" :displayTextThreshold="15"></ste-progress>
73
73
  ```
74
74
 
75
+ #### 阶段配置
76
+
77
+ ```html
78
+ <script lang="ts" setup>
79
+ const stageData = ref({
80
+ 20: { label: '完成进度20%', style: { background: '#F53F3F' } },
81
+ 50: { label: '完成进度50%', style: { background: '#FFC53D' } },
82
+ 100: { label: '当月销售计划20,80万', style: { background: '#077EDB', textAlign: 'right' } },
83
+ });
84
+ </script>
85
+ <ste-progress :percentage="10" strokeWidth="36" :stageData="stageData"></ste-progress>
86
+ ```
87
+
75
88
  ---$
76
89
 
77
90
  ### API
@@ -1,16 +1,22 @@
1
+ import type { PropType } from 'vue';
2
+
1
3
  const progressProps = {
2
- activeBg: { type: [String], default: '' },
3
- inactiveBg: { type: [String], default: '#eeeeee' },
4
- percentage: { type: [Number], default: 0 },
5
- strokeWidth: { type: [String, Number], default: 24 },
6
- disabled: { type: [Boolean], default: false },
7
- width: { type: [String, Number], default: '100%' },
8
- duration: { type: [Number], default: 0.3 },
9
- pivotText: { type: [String], default: '' },
10
- textColor: { type: [String], default: '#ffffff' },
11
- textAlign: { type: [String], default: 'right' },
12
- textSize: { type: [String, Number], default: 16 },
13
- displayTextThreshold: { type: [Number], default: 0 },
14
- }
4
+ activeBg: { type: [String], default: '' },
5
+ inactiveBg: { type: [String], default: '#eeeeee' },
6
+ percentage: { type: [Number], default: 0 },
7
+ strokeWidth: { type: [String, Number], default: 24 },
8
+ disabled: { type: [Boolean], default: false },
9
+ width: { type: [String, Number], default: '100%' },
10
+ duration: { type: [Number], default: 0.3 },
11
+ pivotText: { type: [String], default: '' },
12
+ textColor: { type: [String], default: '#ffffff' },
13
+ textAlign: { type: [String], default: 'right' },
14
+ textSize: { type: [String, Number], default: 16 },
15
+ displayTextThreshold: { type: [Number], default: 0 },
16
+ stageData: {
17
+ type: Object as PropType<Record<string | number, any>>,
18
+ default: () => ({}),
19
+ },
20
+ };
15
21
 
16
- export default progressProps
22
+ export default progressProps;
@@ -75,6 +75,12 @@
75
75
  "description": "显示文本的阈值",
76
76
  "type": "number",
77
77
  "default": "0"
78
+ },
79
+ {
80
+ "name": "stageData",
81
+ "description": "阶段配置信息,该值存在时percentage将不生效",
82
+ "type": "object",
83
+ "default": "{}"
78
84
  }
79
85
  ]
80
86
  }
@@ -5,6 +5,8 @@ import utils from '../../utils/utils';
5
5
  import { useColorStore } from '../../store/color';
6
6
  let { getColor } = useColorStore();
7
7
 
8
+ let hasStage = false;
9
+
8
10
  const slots = useSlots();
9
11
  const props = defineProps(propsData);
10
12
 
@@ -18,20 +20,6 @@ onMounted(() => {
18
20
  haveSlot.value = !!slots.default;
19
21
  });
20
22
 
21
- watch(
22
- () => props.percentage,
23
- val => {
24
- if (val >= MAX) {
25
- realPercentage.value = MAX;
26
- } else if (val <= MIN) {
27
- realPercentage.value = MIN;
28
- } else {
29
- realPercentage.value = val;
30
- }
31
- },
32
- { immediate: true }
33
- );
34
-
35
23
  const cmpRootCssVar = computed(() => {
36
24
  let style: CSSProperties = {
37
25
  '--progress-width': utils.addUnit(props.width),
@@ -83,12 +71,72 @@ const cmpActiveText = computed(() => {
83
71
  }
84
72
  return str;
85
73
  });
74
+
75
+ const getPercentage = (value: number): number => {
76
+ if (!(typeof value === 'number')) {
77
+ return MIN;
78
+ }
79
+ if (value >= MAX) {
80
+ return MAX;
81
+ } else if (value <= MIN) {
82
+ return MIN;
83
+ } else {
84
+ return value;
85
+ }
86
+ };
87
+
88
+ const getStageStyle = (stageValue: number, index: number, value: any): CSSProperties => {
89
+ let style: CSSProperties = { width: `${getPercentage(stageValue)}%`, zIndex: Object.keys(props.stageData).length - index };
90
+
91
+ if (value instanceof Object && value.style) {
92
+ const { background, ...restStyle } = value.style;
93
+ style = {
94
+ ...style,
95
+ ...utils.bg2style(background),
96
+ ...restStyle,
97
+ };
98
+ }
99
+
100
+ return style;
101
+ };
102
+
103
+ const getStageTextWidth = (index: number, value: any): CSSProperties => {
104
+ let style: CSSProperties = { width: '100%' };
105
+ if (index > 0) {
106
+ const stageValues = Object.keys(props.stageData);
107
+ const widthPercentage = (Number(stageValues[index]) - Number(stageValues[index - 1])) / Number(stageValues[index]);
108
+ style.width = `${widthPercentage * 100}%`;
109
+ style.textAlign = value.style?.textAlign;
110
+ }
111
+ return style;
112
+ };
113
+
114
+ watch(
115
+ () => props.stageData,
116
+ val => {
117
+ hasStage = Object.keys(val || {}).length > 0;
118
+ },
119
+ { immediate: true }
120
+ );
121
+
122
+ watch(
123
+ () => props.percentage,
124
+ val => {
125
+ realPercentage.value = getPercentage(val);
126
+ },
127
+ { immediate: true }
128
+ );
86
129
  </script>
87
130
 
88
131
  <template>
89
132
  <view class="ste-progress-root" :style="[cmpRootCssVar]">
90
133
  <view class="inactive-box" :style="[cmpInactiveStyle]"></view>
91
- <view class="active-box line" :style="[cmpActiveStyle]" v-if="realPercentage > 0">
134
+ <view class="stage-box" v-if="hasStage">
135
+ <view class="stage" v-for="(item, index) in Object.keys(stageData)" :style="[getStageStyle(Number(item), index, stageData[item])]">
136
+ <text class="text" :style="[getStageTextWidth(index, stageData[item])]">{{ stageData[item].label }}</text>
137
+ </view>
138
+ </view>
139
+ <view class="active-box line" :style="[cmpActiveStyle]" v-if="realPercentage > 0 && !hasStage">
92
140
  <slot v-if="haveSlot"></slot>
93
141
  <text class="text" v-else>{{ cmpActiveText }}</text>
94
142
  </view>
@@ -102,7 +150,9 @@ const cmpActiveText = computed(() => {
102
150
  height: var(--progress-height);
103
151
 
104
152
  > .inactive-box,
105
- > .active-box {
153
+ > .active-box,
154
+ > .stage-box,
155
+ > .stage-box > .stage {
106
156
  width: var(--progress-width);
107
157
  height: var(--progress-height);
108
158
  border-radius: 24rpx;
@@ -131,5 +181,33 @@ const cmpActiveText = computed(() => {
131
181
  line-height: 0;
132
182
  }
133
183
  }
184
+
185
+ .stage-box {
186
+ position: absolute;
187
+ left: 0;
188
+ top: 0;
189
+
190
+ .stage {
191
+ position: absolute;
192
+ left: 0;
193
+ top: 0;
194
+
195
+ text-align: right;
196
+
197
+ display: flex;
198
+ align-items: center;
199
+ justify-content: flex-end;
200
+ padding: var(--progress-padding) 0;
201
+ .text {
202
+ color: var(--active-text-color);
203
+ font-size: var(--active-text-font-size);
204
+ text-align: center;
205
+
206
+ overflow: hidden; //超出的文本隐藏
207
+ text-overflow: ellipsis; //溢出用省略号显示
208
+ white-space: nowrap; //溢出不换行
209
+ }
210
+ }
211
+ }
134
212
  }
135
213
  </style>
@@ -102,11 +102,13 @@ const loadMore = () => {
102
102
  </scroll-view>
103
103
  </slot>
104
104
  <view class="open-icon-event" @click.stop="clickOpenIcon">
105
- <view class="open-icon">
106
- <view class="open-icon-transform">
107
- <ste-icon code="&#xe676;" size="20" />
105
+ <slot name="icon">
106
+ <view class="open-icon">
107
+ <view class="open-icon-transform">
108
+ <ste-icon code="&#xe676;" size="20" />
109
+ </view>
108
110
  </view>
109
- </view>
111
+ </slot>
110
112
  </view>
111
113
 
112
114
  <view class="clearable-icon" v-if="cmpShowClearable" @click.stop="clickClearable">
@@ -1,6 +1,5 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, computed, onUnmounted, onMounted } from 'vue';
3
- import { toastState } from './toast-bus';
4
3
  defineOptions({
5
4
  name: 'ste-toast',
6
5
  });
@@ -87,21 +86,39 @@ function hideToast() {
87
86
  close.value();
88
87
  }
89
88
 
90
- // 替换为 uni-app 事件监听
91
- onMounted(() => {
92
- uni.$on('ste:toast:show', options => {
93
- showToast(options);
94
- });
89
+ const registEvent = (flag = true) => {
90
+ if (flag) {
91
+ // 注册事件
92
+ uni.$on('ste:toast:show', showToast);
93
+ uni.$on('ste:toast:hide', hideToast);
94
+ } else {
95
+ // 卸载事件
96
+ uni.$off('ste:toast:show');
97
+ uni.$off('ste:toast:hide');
98
+ }
99
+ };
100
+
101
+ // 记录组件挂载时间
102
+ let mountTimestamp = 0;
103
+ // 最短合理的组件生命周期(毫秒)
104
+ // 用于解决APP等某些环境下组件卸载顺序异常,导致事件卸载
105
+ const MIN_REASONABLE_LIFECYCLE = 800;
95
106
 
96
- uni.$on('ste:toast:hide', () => {
97
- hideToast();
98
- });
107
+ onMounted(() => {
108
+ mountTimestamp = Date.now();
109
+ registEvent(false);
110
+ setTimeout(() => {
111
+ registEvent();
112
+ }, 200);
99
113
  });
100
114
 
101
- // 记得在组件卸载时移除事件监听
102
115
  onUnmounted(() => {
103
- uni.$off('ste:toast:show');
104
- uni.$off('ste:toast:hide');
116
+ // 计算组件生命周期时长
117
+ const lifecycleDuration = Date.now() - mountTimestamp;
118
+ // 只有当组件存活时间合理时,才考虑卸载事件监听
119
+ if (lifecycleDuration >= MIN_REASONABLE_LIFECYCLE) {
120
+ registEvent(false);
121
+ }
105
122
  });
106
123
 
107
124
  defineExpose({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stellar-ui-plus",
3
- "version": "1.17.15",
3
+ "version": "1.17.17",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -11,7 +11,8 @@
11
11
  },
12
12
  "scripts": {
13
13
  "test": "echo \"Error: no test specified\" && exit 1",
14
- "publish-vscode-plugin": "cd ../../../plugins/ste-helper & pnpm run publish"
14
+ "publish-vscode-plugin": "cd ../../../plugins/ste-helper & pnpm run publish",
15
+ "prepublishOnly": "pnpm run publish-vscode-plugin"
15
16
  },
16
17
  "dependencies": {
17
18
  "dayjs": "^1.11.11"
@@ -1,15 +0,0 @@
1
- import { ref } from 'vue';
2
-
3
- export const toastState = ref({
4
- show: false,
5
- title: '',
6
- icon: 'success',
7
- image: '',
8
- duration: 1500,
9
- mask: false,
10
- success: undefined,
11
- fail: undefined,
12
- complete: undefined,
13
- close: undefined,
14
- order: false,
15
- });