hy-app 0.5.6 → 0.5.8
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.
- package/components/hy-card/index.scss +73 -0
- package/components/hy-float-button/hy-float-button.vue +10 -11
- package/components/hy-float-button/index.scss +12 -12
- package/components/hy-input/hy-input.vue +0 -1
- package/components/hy-rolling-num/README.md +137 -0
- package/components/hy-rolling-num/hy-rolling-num.vue +198 -0
- package/components/hy-rolling-num/index.scss +34 -0
- package/components/hy-rolling-num/props.ts +68 -0
- package/components/hy-rolling-num/typing.d.ts +0 -0
- package/components/hy-status-bar/typing.d.ts +12 -0
- package/components/hy-sticky/hy-sticky.vue +226 -0
- package/components/hy-sticky/index.scss +29 -0
- package/components/hy-sticky/props.ts +24 -0
- package/components/hy-sticky/typing.d.ts +4 -0
- package/components/hy-tabbar/hy-tabbar.vue +0 -1
- package/components/hy-tabbar-group/index.scss +56 -56
- package/components/hy-tabbar-item/index.scss +42 -42
- package/components/hy-tabbar-item/props.ts +24 -24
- package/components/hy-tabs/hy-tabs.vue +21 -23
- package/global.d.ts +1 -0
- package/package.json +2 -2
- package/web-types.json +1 -1
- /package/components/hy-tabbar-group/{typing.ts → typing.d.ts} +0 -0
- /package/components/hy-tabbar-item/{typing.ts → typing.d.ts} +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
@use "../../libs/css/mixin.scss" as *;
|
|
2
|
+
@use "../../libs/css/theme" as *;
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@include b(card) {
|
|
6
|
+
position: relative;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
font-size: 28rpx;
|
|
9
|
+
background-color: $hy-background--container;
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
|
|
12
|
+
@include e(full) {
|
|
13
|
+
margin-left: $hy-border-margin-padding-base !important;
|
|
14
|
+
margin-right: $hy-border-margin-padding-base !important;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@include m(border) {
|
|
18
|
+
@include pseudo(after) {
|
|
19
|
+
border-radius: 16rpx;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* 头部 */
|
|
24
|
+
@include e(head) {
|
|
25
|
+
padding: 20rpx 20rpx 10rpx;
|
|
26
|
+
@include m(flex) {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: space-between;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@include m(left) {
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
flex: 1;
|
|
36
|
+
|
|
37
|
+
@include edeep(thumb) {
|
|
38
|
+
margin-right: $hy-border-margin-padding-base;
|
|
39
|
+
flex-shrink: 0
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@include e(title) {
|
|
43
|
+
max-width: 400rpx;
|
|
44
|
+
font-size: $hy-font-size-base;
|
|
45
|
+
@include lineEllipsis;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@include e(sub) {
|
|
49
|
+
color: $hy-text-color--grey;
|
|
50
|
+
font-size: $hy-font-size-sm;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@include m(right) {
|
|
55
|
+
color: $hy-text-color--grey;
|
|
56
|
+
margin-left: $hy-border-margin-padding-sm;
|
|
57
|
+
|
|
58
|
+
@include e(text) {
|
|
59
|
+
white-space: nowrap;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* 身体 */
|
|
65
|
+
@include e(body) {
|
|
66
|
+
padding: 10rpx 20rpx 10rpx;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* 尾部 */
|
|
70
|
+
@include e(foot) {
|
|
71
|
+
padding: 10rpx 20rpx 20rpx;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -79,7 +79,7 @@ import { computed, getCurrentInstance, onMounted, ref, reactive, watch } from 'v
|
|
|
79
79
|
import type { CSSProperties } from 'vue'
|
|
80
80
|
import type { IFloatButtonEmits } from './typing'
|
|
81
81
|
import type { MenusType } from './typing'
|
|
82
|
-
import { addUnit, getPx, getRect, guid, isH5 } from '../../libs'
|
|
82
|
+
import { addUnit, debounce, getPx, getRect, guid, isH5, throttle } from '../../libs'
|
|
83
83
|
import floatButtonProps from './props'
|
|
84
84
|
// 组件
|
|
85
85
|
import HyIcon from '../hy-icon/hy-icon.vue'
|
|
@@ -133,7 +133,7 @@ watch(
|
|
|
133
133
|
)
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
|
-
*
|
|
136
|
+
* 初始化距离
|
|
137
137
|
* */
|
|
138
138
|
const initPosition = () => {
|
|
139
139
|
const { minLeft, minTop, maxLeft, maxTop } = bounding
|
|
@@ -193,7 +193,7 @@ const initPosition = () => {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
|
-
*
|
|
196
|
+
* 获取组件大小
|
|
197
197
|
* */
|
|
198
198
|
const getFloatBtnSize = computed(() => {
|
|
199
199
|
if (typeof props.size === 'string' && Object.keys(btnSize).includes(props.size)) {
|
|
@@ -204,16 +204,15 @@ const getFloatBtnSize = computed(() => {
|
|
|
204
204
|
})
|
|
205
205
|
|
|
206
206
|
/**
|
|
207
|
-
*
|
|
207
|
+
* 悬浮按钮样式
|
|
208
208
|
* */
|
|
209
209
|
const FloatButtonStyle = computed(() => {
|
|
210
210
|
const style: CSSProperties = {
|
|
211
|
-
top: currentCoordinate.top
|
|
212
|
-
left: currentCoordinate.left
|
|
211
|
+
top: `${currentCoordinate.top}px`,
|
|
212
|
+
left: `${currentCoordinate.left}px`,
|
|
213
213
|
backgroundColor: props.bgColor,
|
|
214
214
|
zIndex: props.zIndex,
|
|
215
|
-
color: props.textColor
|
|
216
|
-
transition: 'all ease 0.3s'
|
|
215
|
+
color: props.textColor
|
|
217
216
|
}
|
|
218
217
|
if (props.fixed) style.position = 'fixed'
|
|
219
218
|
|
|
@@ -267,7 +266,7 @@ const menusStyle = computed(() => {
|
|
|
267
266
|
})
|
|
268
267
|
|
|
269
268
|
/**
|
|
270
|
-
*
|
|
269
|
+
* 获取悬浮按钮大小
|
|
271
270
|
* */
|
|
272
271
|
const getFatRect = () => {
|
|
273
272
|
return new Promise((resolve, reject) => {
|
|
@@ -285,7 +284,7 @@ const getFatRect = () => {
|
|
|
285
284
|
}
|
|
286
285
|
|
|
287
286
|
/**
|
|
288
|
-
*
|
|
287
|
+
* 点击悬浮按钮
|
|
289
288
|
* */
|
|
290
289
|
const handleClick = () => {
|
|
291
290
|
emit('click')
|
|
@@ -295,7 +294,7 @@ const handleClick = () => {
|
|
|
295
294
|
}
|
|
296
295
|
|
|
297
296
|
/**
|
|
298
|
-
*
|
|
297
|
+
* 点击单条菜单栏
|
|
299
298
|
* */
|
|
300
299
|
const handleMenuItemClick = (temp: MenusType, index: number) => {
|
|
301
300
|
emit('clickItem', temp, index)
|
|
@@ -14,18 +14,18 @@
|
|
|
14
14
|
box-shadow: $hy-box-shadow;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
17
|
+
//@include e(animation) {
|
|
18
|
+
// animation: floatAnimation 2s ease-in-out infinite;
|
|
19
|
+
// @keyframes floatAnimation {
|
|
20
|
+
// 0%,
|
|
21
|
+
// 100% {
|
|
22
|
+
// transform: translateY(0); /* 初始位置 */
|
|
23
|
+
// }
|
|
24
|
+
// 50% {
|
|
25
|
+
// transform: translateY(-20px); /* 上浮20像素 */
|
|
26
|
+
// }
|
|
27
|
+
// }
|
|
28
|
+
//}
|
|
29
29
|
|
|
30
30
|
@include e(container) {
|
|
31
31
|
border-radius: 50%;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# hy-rolling-num 滚动数字组件
|
|
2
|
+
|
|
3
|
+
## 介绍
|
|
4
|
+
|
|
5
|
+
滚动数字组件,用于实现数字从初始值(全0)平滑滚动到目标值的动画效果。当数字变化时,会先显示与目标值长度相同的全0字符串,然后通过平滑的滚动动画过渡到目标值。
|
|
6
|
+
|
|
7
|
+
## 特性
|
|
8
|
+
|
|
9
|
+
- 支持自定义数字大小、颜色、字体粗细
|
|
10
|
+
- 支持设置滚动方向(向上、向下、交替)
|
|
11
|
+
- 支持设置动画持续时间和延迟步进
|
|
12
|
+
- 自动根据目标值长度生成对应长度的初始值(全0)
|
|
13
|
+
- 支持特殊字符(非数字字符会直接显示,不会参与滚动)
|
|
14
|
+
|
|
15
|
+
## 使用方法
|
|
16
|
+
|
|
17
|
+
### 基本用法
|
|
18
|
+
|
|
19
|
+
```vue
|
|
20
|
+
<template>
|
|
21
|
+
<view class="demo">
|
|
22
|
+
<hy-rolling-num :value="num" :size="'48rpx'" :color="'#1989fa'" />
|
|
23
|
+
</view>
|
|
24
|
+
</template>
|
|
25
|
+
|
|
26
|
+
<script setup lang="ts">
|
|
27
|
+
import { ref } from 'vue';
|
|
28
|
+
import HyRollingNum from '@/package/components/hy-rolling-num/hy-rolling-num.vue';
|
|
29
|
+
|
|
30
|
+
// 初始值为0,当更新为234564时,会先显示000000然后滚动到234564
|
|
31
|
+
const num = ref(234564);
|
|
32
|
+
</script>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 自定义配置
|
|
36
|
+
|
|
37
|
+
```vue
|
|
38
|
+
<hy-rolling-num
|
|
39
|
+
:value="num"
|
|
40
|
+
:size="'36rpx'"
|
|
41
|
+
:color="'#ff6b6b'"
|
|
42
|
+
:font-weight="'bold'"
|
|
43
|
+
:duration="2"
|
|
44
|
+
:scroll-direction="'down'"
|
|
45
|
+
:stop-order="'right-to-left'"
|
|
46
|
+
:delay-step="0.15"
|
|
47
|
+
/>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Props
|
|
51
|
+
|
|
52
|
+
| 参数名 | 类型 | 默认值 | 说明 |
|
|
53
|
+
|--------|------|--------|------|
|
|
54
|
+
| value | number \| string | 0 | 要显示的数字或字符串值 |
|
|
55
|
+
| size | string | '32rpx' | 数字字体大小 |
|
|
56
|
+
| color | string | '#333' | 数字颜色 |
|
|
57
|
+
| fontWeight | string \| number | 'normal' | 字体粗细 |
|
|
58
|
+
| height | string | '40rpx' | 单个数字的高度 |
|
|
59
|
+
| duration | number | 1.5 | 滚动动画持续时间(秒) |
|
|
60
|
+
| letterSpacing | string | '0' | 数字间距 |
|
|
61
|
+
| scrollDirection | 'up' \| 'down' \| 'alternate' | 'up' | 滚动方向:向上、向下或交替 |
|
|
62
|
+
| stopOrder | 'left-to-right' \| 'right-to-left' | 'left-to-right' | 滚动停止顺序:从左到右或从右到左 |
|
|
63
|
+
| delayStep | number | 0.1 | 每个数字滚动的延迟时间间隔(秒) |
|
|
64
|
+
| customStyle | CSSProperties | {} | 自定义样式对象 |
|
|
65
|
+
|
|
66
|
+
## 示例
|
|
67
|
+
|
|
68
|
+
### 示例1:基本滚动效果
|
|
69
|
+
|
|
70
|
+
```vue
|
|
71
|
+
<template>
|
|
72
|
+
<view>
|
|
73
|
+
<text>滚动数字:</text>
|
|
74
|
+
<hy-rolling-num :value="234564" />
|
|
75
|
+
<!-- 会先显示 000000,然后滚动到 234564 -->
|
|
76
|
+
</view>
|
|
77
|
+
</template>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 示例2:改变数字长度
|
|
81
|
+
|
|
82
|
+
```vue
|
|
83
|
+
<template>
|
|
84
|
+
<view>
|
|
85
|
+
<button @click="changeValue(234)">显示 234</button>
|
|
86
|
+
<button @click="changeValue(987654321)">显示 987654321</button>
|
|
87
|
+
<hy-rolling-num :value="displayValue" />
|
|
88
|
+
<!-- 点击第一个按钮:显示 000 -> 234 -->
|
|
89
|
+
<!-- 点击第二个按钮:显示 000000000 -> 987654321 -->
|
|
90
|
+
</view>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<script setup lang="ts">
|
|
94
|
+
import { ref } from 'vue';
|
|
95
|
+
|
|
96
|
+
const displayValue = ref(0);
|
|
97
|
+
|
|
98
|
+
const changeValue = (val: number) => {
|
|
99
|
+
displayValue.value = val;
|
|
100
|
+
};
|
|
101
|
+
</script>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 示例3:自定义滚动方向和动画
|
|
105
|
+
|
|
106
|
+
```vue
|
|
107
|
+
<template>
|
|
108
|
+
<view>
|
|
109
|
+
<hy-rolling-num
|
|
110
|
+
:value="num"
|
|
111
|
+
:scroll-direction="'alternate'"
|
|
112
|
+
:duration="1.2"
|
|
113
|
+
:delay-step="0.08"
|
|
114
|
+
/>
|
|
115
|
+
<!-- 交替方向滚动,奇偶位滚动方向相反 -->
|
|
116
|
+
</view>
|
|
117
|
+
</template>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 注意事项
|
|
121
|
+
|
|
122
|
+
1. 组件会自动根据传入的 `value` 长度生成对应长度的全0初始值
|
|
123
|
+
2. 当 `value` 为字符串时,非数字字符会直接显示,不会参与滚动动画
|
|
124
|
+
3. 滚动动画的实现依赖于CSS的transform属性,确保在支持该属性的环境中使用
|
|
125
|
+
4. 动画延迟时间总和不宜过长,以免影响用户体验
|
|
126
|
+
5. 当需要频繁更新数字时,建议控制更新频率,避免动画效果过于密集
|
|
127
|
+
|
|
128
|
+
## 常见问题
|
|
129
|
+
|
|
130
|
+
### Q: 为什么数字变化时会先显示全0?
|
|
131
|
+
A: 这是组件的设计特性,用于实现从初始状态到目标状态的滚动动画效果,增强视觉体验。
|
|
132
|
+
|
|
133
|
+
### Q: 如何调整滚动速度?
|
|
134
|
+
A: 通过调整 `duration` 属性可以控制整个滚动动画的持续时间,数值越小,滚动越快。
|
|
135
|
+
|
|
136
|
+
### Q: 特殊字符会如何显示?
|
|
137
|
+
A: 非数字字符(如小数点、货币符号等)会直接显示,不会参与滚动动画。
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view :class="['hy-rolling-num', customClass]" :style="containerStyle">
|
|
3
|
+
<view
|
|
4
|
+
v-for="(item, index) in renderList"
|
|
5
|
+
:key="index"
|
|
6
|
+
class="hy-rolling-num__column"
|
|
7
|
+
:style="{ height: addUnit(height), marginRight: letterSpacing }"
|
|
8
|
+
>
|
|
9
|
+
<view
|
|
10
|
+
v-if="item.isDigit"
|
|
11
|
+
class="hy-rolling-num__column--wrapper"
|
|
12
|
+
:style="{
|
|
13
|
+
transform: item.transformValue,
|
|
14
|
+
transition: `transform ${duration}s cubic-bezier(0.25, 1, 0.5, 1)`,
|
|
15
|
+
transitionDelay: item.delay,
|
|
16
|
+
height: '1200%' /* 12个数字,总高度1200% */
|
|
17
|
+
}"
|
|
18
|
+
>
|
|
19
|
+
<text
|
|
20
|
+
v-for="(num, idx) in item.strip"
|
|
21
|
+
:key="idx"
|
|
22
|
+
class="hy-rolling-num__column--wrapper__digit"
|
|
23
|
+
:style="textStyle"
|
|
24
|
+
>
|
|
25
|
+
{{ num }}
|
|
26
|
+
</text>
|
|
27
|
+
</view>
|
|
28
|
+
|
|
29
|
+
<view
|
|
30
|
+
v-else
|
|
31
|
+
class="hy-rolling-num__column--symbol"
|
|
32
|
+
:style="{ height: addUnit(height), ...textStyleObject }"
|
|
33
|
+
>
|
|
34
|
+
{{ item.val }}
|
|
35
|
+
</view>
|
|
36
|
+
</view>
|
|
37
|
+
</view>
|
|
38
|
+
</template>
|
|
39
|
+
|
|
40
|
+
<script lang="ts">
|
|
41
|
+
export default {
|
|
42
|
+
name: 'hy-rolling-num',
|
|
43
|
+
options: {
|
|
44
|
+
addGlobalClass: true,
|
|
45
|
+
virtualHost: true,
|
|
46
|
+
styleIsolation: 'shared'
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<script setup lang="ts">
|
|
52
|
+
import { computed, ref, watch, type CSSProperties } from 'vue'
|
|
53
|
+
import { addUnit } from '../../libs'
|
|
54
|
+
import rollingNumProps from './props'
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 滚动数字组件,用于实现数字从初始值(全0)平滑滚动到目标值的动画效果。
|
|
58
|
+
* @displayName hy-rolling-num
|
|
59
|
+
*/
|
|
60
|
+
defineOptions({})
|
|
61
|
+
|
|
62
|
+
const props = defineProps(rollingNumProps)
|
|
63
|
+
|
|
64
|
+
// --- 核心逻辑:计算每列的配置 ---
|
|
65
|
+
|
|
66
|
+
// **【修改点 1】** 定义包含冗余数字的数字条
|
|
67
|
+
// 现在数字条有 12 个元素,每个元素占据 1/12 ≈ 8.33% 的高度
|
|
68
|
+
const BASE_STRIP = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
|
|
69
|
+
const ITEM_HEIGHT_PERCENT = 100 / BASE_STRIP.length // 8.333%
|
|
70
|
+
|
|
71
|
+
// 添加内部状态管理,用于控制初始值和目标值的切换
|
|
72
|
+
const displayValue = ref('')
|
|
73
|
+
|
|
74
|
+
// 监听value变化,实现从初始值到目标值的滚动
|
|
75
|
+
watch(
|
|
76
|
+
() => props.value,
|
|
77
|
+
(newValue) => {
|
|
78
|
+
const newValueStr = String(newValue)
|
|
79
|
+
const newValueLen = newValueStr.length
|
|
80
|
+
|
|
81
|
+
// 创建对应长度的全0初始值
|
|
82
|
+
const initialValue = '0'.repeat(newValueLen)
|
|
83
|
+
|
|
84
|
+
// 先显示初始值
|
|
85
|
+
displayValue.value = initialValue
|
|
86
|
+
|
|
87
|
+
// 延迟一段时间后再显示目标值,以触发滚动动画
|
|
88
|
+
// 100ms是一个比较合理的值,确保DOM有足够时间更新
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
displayValue.value = newValueStr
|
|
91
|
+
}, 100)
|
|
92
|
+
},
|
|
93
|
+
{ immediate: true }
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
const renderList = computed(() => {
|
|
97
|
+
const str = displayValue.value
|
|
98
|
+
const len = str.length
|
|
99
|
+
const arr = []
|
|
100
|
+
|
|
101
|
+
// 正序 stripUp (用于 'up'):数字顺序为 9 0 1 ... 9 0
|
|
102
|
+
const stripUp = BASE_STRIP
|
|
103
|
+
// 倒序 stripDown (用于 'down' 或 'alternate'):数字顺序为 0 9 8 ... 1 0 9
|
|
104
|
+
const stripDown = [...BASE_STRIP].reverse()
|
|
105
|
+
|
|
106
|
+
for (let i = 0; i < len; i++) {
|
|
107
|
+
const char = str[i]
|
|
108
|
+
const isDigit = /^\d$/.test(char)
|
|
109
|
+
const digitVal = isDigit ? parseInt(char, 10) : 0
|
|
110
|
+
|
|
111
|
+
// 1. 确定当前列的滚动方向
|
|
112
|
+
let isReversed = props.scrollDirection === 'down'
|
|
113
|
+
if (props.scrollDirection === 'alternate') {
|
|
114
|
+
isReversed = i % 2 !== 0
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 2. 根据方向决定使用哪种数字条
|
|
118
|
+
const currentStrip = isReversed ? stripDown : stripUp
|
|
119
|
+
|
|
120
|
+
// 3. 计算 Transform 位移:找到目标数字在数字条中的索引位置
|
|
121
|
+
// **【修改点 2】**
|
|
122
|
+
// 目标数字总是存在两次 (0-9)
|
|
123
|
+
// - 向上滚动 ('up') 时,使用 **第二个** 匹配的索引,即 0~9 的正常排列部分。
|
|
124
|
+
// - 向下滚动 ('down') 时,使用 **第一个** 匹配的索引。
|
|
125
|
+
let targetIndex = -1
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
props.scrollDirection === 'up' ||
|
|
129
|
+
(props.scrollDirection === 'alternate' && !isReversed)
|
|
130
|
+
) {
|
|
131
|
+
// 向上滚:目标是中间的 0-9 部分 (索引 1 到 10)
|
|
132
|
+
// 查找 0 到 9 中间的那个索引
|
|
133
|
+
targetIndex = currentStrip.indexOf(digitVal, 1)
|
|
134
|
+
} else {
|
|
135
|
+
// 向下滚或交替的反向滚:目标是中间的 0-9 部分
|
|
136
|
+
// 查找 0 到 9 中间的那个索引
|
|
137
|
+
// 查找第一个数字,如果是 0,则目标是索引 10 (倒数第二个)
|
|
138
|
+
targetIndex = currentStrip.lastIndexOf(digitVal, currentStrip.length - 2)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 确保找到了有效索引
|
|
142
|
+
if (targetIndex === -1) {
|
|
143
|
+
// 理论上不会发生,作为降级处理
|
|
144
|
+
targetIndex = currentStrip.indexOf(digitVal)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const transformValue = `translate3d(0, -${targetIndex * ITEM_HEIGHT_PERCENT}%, 0)`
|
|
148
|
+
|
|
149
|
+
// 4. 计算延迟 (Staggering)
|
|
150
|
+
let delaySec = 0
|
|
151
|
+
if (props.stopOrder === 'ltr') {
|
|
152
|
+
delaySec = i * props.delayStep
|
|
153
|
+
} else {
|
|
154
|
+
delaySec = (len - 1 - i) * props.delayStep
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
arr.push({
|
|
158
|
+
val: char,
|
|
159
|
+
isDigit,
|
|
160
|
+
strip: currentStrip,
|
|
161
|
+
transformValue,
|
|
162
|
+
delay: `${delaySec}s`
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
return arr
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
// --- 样式计算部分省略,但注意要用到 ITEM_HEIGHT_PERCENT ---
|
|
169
|
+
|
|
170
|
+
const containerStyle = computed<CSSProperties>(() => ({
|
|
171
|
+
display: 'flex',
|
|
172
|
+
flexDirection: 'row',
|
|
173
|
+
alignItems: 'center',
|
|
174
|
+
overflow: 'hidden'
|
|
175
|
+
}))
|
|
176
|
+
|
|
177
|
+
const textStyleObject = computed<CSSProperties>(() => ({
|
|
178
|
+
fontSize: addUnit(props.size),
|
|
179
|
+
color: props.color,
|
|
180
|
+
fontWeight: props.fontWeight,
|
|
181
|
+
lineHeight: addUnit(props.height),
|
|
182
|
+
...props.customStyle
|
|
183
|
+
}))
|
|
184
|
+
|
|
185
|
+
const textStyle = computed(() => {
|
|
186
|
+
let s = ''
|
|
187
|
+
const obj = textStyleObject.value
|
|
188
|
+
for (const key in obj) {
|
|
189
|
+
// @ts-ignore
|
|
190
|
+
s += `${key}:${obj[key]};`
|
|
191
|
+
}
|
|
192
|
+
return s
|
|
193
|
+
})
|
|
194
|
+
</script>
|
|
195
|
+
|
|
196
|
+
<style lang="scss" scoped>
|
|
197
|
+
@import './index.scss';
|
|
198
|
+
</style>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
@use "../../libs/css/mixin.scss" as *;
|
|
2
|
+
|
|
3
|
+
@include b(rolling-num) {
|
|
4
|
+
white-space: nowrap;
|
|
5
|
+
|
|
6
|
+
@include e(column) {
|
|
7
|
+
position: relative;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
display: inline-block;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@include m(wrapper) {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
will-change: transform;
|
|
16
|
+
|
|
17
|
+
@include e(digit) {
|
|
18
|
+
display: flex;
|
|
19
|
+
justify-content: center;
|
|
20
|
+
align-items: center;
|
|
21
|
+
/* 100% / 12 个数字 = 8.3333% */
|
|
22
|
+
height: 8.3333%;
|
|
23
|
+
flex-shrink: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@include m(symbol) {
|
|
29
|
+
display: flex;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
align-items: center;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { CSSProperties, PropType } from 'vue'
|
|
2
|
+
|
|
3
|
+
const rollingNumProps = {
|
|
4
|
+
/** 要显示的数字或字符串值 */
|
|
5
|
+
value: {
|
|
6
|
+
type: [String, Number],
|
|
7
|
+
default: 0
|
|
8
|
+
},
|
|
9
|
+
/** 数字字体大小 */
|
|
10
|
+
size: {
|
|
11
|
+
type: [String, Number],
|
|
12
|
+
default: '32rpx'
|
|
13
|
+
},
|
|
14
|
+
/** 数字颜色 */
|
|
15
|
+
color: {
|
|
16
|
+
type: String,
|
|
17
|
+
default: '#333'
|
|
18
|
+
},
|
|
19
|
+
/** 字体粗细 */
|
|
20
|
+
fontWeight: {
|
|
21
|
+
type: [String, Number],
|
|
22
|
+
default: 'normal'
|
|
23
|
+
},
|
|
24
|
+
/** 单个数字的高度 */
|
|
25
|
+
height: {
|
|
26
|
+
type: [String, Number],
|
|
27
|
+
default: '40rpx'
|
|
28
|
+
},
|
|
29
|
+
/** 滚动动画持续时间(秒) */
|
|
30
|
+
duration: {
|
|
31
|
+
type: Number,
|
|
32
|
+
default: 1.5
|
|
33
|
+
},
|
|
34
|
+
/** 数字间距 */
|
|
35
|
+
letterSpacing: {
|
|
36
|
+
type: [String, Number],
|
|
37
|
+
default: 0
|
|
38
|
+
},
|
|
39
|
+
/**
|
|
40
|
+
* 滚动方向:向上、向下或交替
|
|
41
|
+
* @values up,down,alternate
|
|
42
|
+
* */
|
|
43
|
+
scrollDirection: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: 'up'
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
* 滚动停止顺序:从左到右或从右到左
|
|
49
|
+
* @values ltr,rtl
|
|
50
|
+
* */
|
|
51
|
+
stopOrder: {
|
|
52
|
+
type: String,
|
|
53
|
+
default: 'ltr'
|
|
54
|
+
},
|
|
55
|
+
/** 每个数字滚动的延迟时间间隔(秒) */
|
|
56
|
+
delayStep: {
|
|
57
|
+
type: Number,
|
|
58
|
+
default: 0.1
|
|
59
|
+
},
|
|
60
|
+
/** 定义需要用到的外部样式 */
|
|
61
|
+
customStyle: {
|
|
62
|
+
type: Object as PropType<CSSProperties>
|
|
63
|
+
},
|
|
64
|
+
/** 自定义外部类名 */
|
|
65
|
+
customClass: String
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default rollingNumProps
|
|
File without changes
|