彆扭的滑動條 slider
很有個性的滑動條 ( ´థ౪థ)
使用範例
基本用法
可以自定義滑動邏輯
往右拉很快、往左拉很慢,滑鼠太近時握把會落跑 ԅ(´∀` ԅ)
value: 0
查看範例原始碼
vue
<template>
<div class="w-full flex flex-col gap-4 py-14">
value: {{ data }}
<slider-awkward
v-model="data"
:physical-data="physicalDataStrategy"
/>
</div>
</template>
<script setup lang="ts">
import type { ComponentProps } from 'vue-component-type-helpers'
import { ref } from 'vue'
import SliderAwkward from '../slider-awkward.vue'
type Props = ComponentProps<typeof SliderAwkward>
const data = ref(0)
const physicalDataStrategy: Props['physicalData'] = (params) => {
const { velocity, value, targetValue, pointerPosition } = params
if (pointerPosition.x < -50) {
return {
acceleration: -0.0001,
maxSpeed: velocity > 0 ? 0.05 : 1,
}
}
if (targetValue <= value) {
return {
acceleration: 0.001,
maxSpeed: 5,
}
}
const sign = Math.sign(targetValue - value)
return {
velocity: sign * 9999,
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
預算表
讓客人好好思考思考 („ಡωಡ )
$10,000
查看範例原始碼
vue
<template>
<div class="w-full flex flex-col gap-4 py-14">
${{ money }}
<slider-awkward
v-model="data"
:physical-data="physicalDataStrategy"
:min="1000"
:step="100"
:max
/>
</div>
</template>
<script setup lang="ts">
import type { ComponentProps } from 'vue-component-type-helpers'
import { computed, ref } from 'vue'
import SliderAwkward from '../slider-awkward.vue'
type Props = ComponentProps<typeof SliderAwkward>
const max = 1000000
const data = ref(10000)
const money = computed(() => data.value.toLocaleString())
const stuckThreshold = max / 10 * 8
const physicalDataStrategy: Props['physicalData'] = (params) => {
const { value, targetValue } = params
if (value > stuckThreshold) {
return {
stuckAt: max,
escapeValue: max / 3 * 2,
}
}
if (targetValue > value) {
return {
velocity: 100,
}
}
return {
acceleration: -0.0001,
maxSpeed: 0.01,
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
原理
移動基於物理模擬
原始碼
API
Props
export type PhysicalData = {
/** px/ms */
velocity: number;
} | {
/** px/ms^2 */
acceleration: number;
/** 可限制最大速度,僅為正數 */
maxSpeed?: number;
} | {
/** 卡在指定數值,限制於 min、max 之間 */
stuckAt: number;
/** 滑鼠拉動目標數值之差大於此值即可掙脫,掙脫後 thumb 會移動至此 */
escapeValue: number;
}
export interface Props {
modelValue: number;
disabled?: boolean;
min?: number;
max?: number;
step?: number;
thumbSize?: number;
thumbColor?: string;
trackClass?: string;
/** 物理參數,可以控制移動方式
*
* 如果是函式,則會在每次動畫更新時呼叫
*/
physicalData?: PhysicalData | ((data: {
/** 目前移動速度 */
velocity: number;
/** 目前數值 */
value: number;
/** 目標數值 */
targetValue: number;
/** 目前比例 */
ratio: number;
/** 滑鼠在 slider 上的比例 */
pointerRatio: number;
/** 以 thumb 中心點為 (0, 0) */
pointerPosition: { x: number; y: number };
}) => PhysicalData);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Emits
const emit = defineEmits<{
'update:modelValue': [value: Props['modelValue']];
}>()
1
2
3
2
3