Fragile Slider slider
Yes, it breaks. (´・ω・`)
Examples
Basic Usage
Pull it too far and the handle snaps off! (´・ω・`)
View Example Source Code
<template>
<div class="w-full flex flex-col gap-4 py-14">
value: {{ Math.floor(value) }}
<slider-stubborn
v-model="value"
class="w-full"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import SliderStubborn from '../slider-fragile.vue'
const value = ref(50)
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Repair & Snap
You can break it on purpose... or fix it if you’re feeling kind. (´・ω・`)ノ
View Example Source Code
<template>
<div class="w-full flex flex-col gap-4">
<div class="w-full py-12">
<slider-stubborn
ref="slider"
v-model="value"
class="w-full"
durable
thumb-color="#34c600"
joint-color="#a0d48e"
/>
</div>
<div class="flex gap-4">
<base-btn
:label="t('repair')"
class="flex-1"
@click="sliderRef?.repair()"
/>
<base-btn
:label="t('break')"
class="flex-1"
@click="sliderRef?.break()"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import BaseBtn from '../../base-btn.vue'
import SliderStubborn from '../slider-fragile.vue'
const sliderRef = useTemplateRef('slider')
const value = ref(50)
const { t } = useI18n()
</script>
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
Sweetness Preference
Unyielding sweetness level! ◝(´・ω・`)◟
View Example Source Code
<template>
<div class="w-full flex flex-col gap-6 py-6">
<div class="flex flex-col items-start gap-4 border border-gray-300 rounded-xl p-6">
<div class="font-bold">
{{ t('drinkType') }}
</div>
<div class="w-full flex flex-wrap justify-between gap-4 whitespace-nowrap">
<label
v-for="item, i in list"
:key="i"
>
<input
v-model="value"
type="radio"
:value="item"
/>
{{ t(`drinkOptions.${item}`) }}
</label>
</div>
</div>
<div class="grid grid-cols-6 w-full flex-nowrap items-center gap-8">
<div class="col-span-2 text-lg">
{{ t('sweetness') }}:10 {{ t('points') }}
</div>
<div class="col-span-4 pr-4">
<slider-stubborn
ref="slider"
:model-value="10"
disabled
:max="10"
/>
</div>
</div>
<div class="grid grid-cols-6 w-full flex-nowrap items-center gap-8">
<div class="col-span-2 text-lg">
{{ t('ice') }}:{{ iceValue }} {{ t('points') }}
</div>
<div class="col-span-4 pr-4">
<slider-stubborn
v-model="iceValue"
durable
:step="3"
:max="9"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, useTemplateRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import SliderStubborn from '../slider-fragile.vue'
const sliderRef = useTemplateRef('slider')
const { t } = useI18n()
const value = ref('綠茶')
const list = [
'綠茶',
'紅茶',
'蜂蜜奶茶',
'鮮奶茶',
'泰奶',
'水果茶',
'檸檬茶',
]
const iceValue = ref(0)
watch(value, () => {
sliderRef.value?.repair()
})
</script>
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
How It Works
This slider is made up of two main components:
Main Body (slider-fragile.vue
)
Handles the core logic—calculating values, detecting mouse interactions, and sending that info (like ratio
and isHeld
) to the thumb component.
The Thumb (slider-fragile-thumb.vue
)
This is where all the drama happens: breaking, shaking, and flying off into the void.
When the user clicks and drags the thumb (isHeld
is true
), we measure how far the mouse is from the thumb’s center.
The farther it gets, the shakier it becomes—like it’s being yanked hard.
Here are its main states:
- Normal: The thumb is neatly positioned using the
ratio
from the parent component. - Broken: If dragged too far (beyond
breakLength
) and held long enough (minSecondsToBreak
), the thumb snaps.isBroken
turnstrue
. - After Breaking:
- When the mouse is released, physics kicks in: it launches with initial velocity (based on your dragging), then falls with gravity, bounces off screen edges, and slows down until it... naps. (
thumbData.sleep
) - You can click and drag it again, and it’ll float around with your mouse.
- When the mouse is released, physics kicks in: it launches with initial velocity (based on your dragging), then falls with gravity, bounces off screen edges, and slows down until it... naps. (
A quirky detail: while in the normal state, the thumb uses absolute
positioning; once broken, it switches to fixed
so it can freely roam the screen.
API
Props
interface Props {
modelValue: number;
disabled?: boolean;
min?: number;
max?: number;
step?: number;
thumbSize?: number;
thumbColor?: string;
jointColor?: string;
trackClass?: string;
durable?: boolean;
breakLength?: number;
minSecondsToBreak?: number;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
Emits
const emit = defineEmits<{
'update:modelValue': [value: Props['modelValue']];
}>()
2
3
Methods
interface Expose {
repair: () => void;
break: () => void;
}
2
3
4