Skip to content

固執的滑動條 slider

停用時絕不妥協的滑動條。(。-`ω´-)

使用範例

基本用法

當狀態為 disabled 時,拉動握把會越拉越長,還會越拉越緊。ᕕ( ゚ ∀。)ᕗ

目前數值:50
查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-4 border border-gray-300 p-6">
    <base-checkbox
      v-model="disabled"
      class="w-full border rounded p-4"
      label="停用"
    />

    <div class="flex flex-col flex-1 justify-center">
      目前數值:{{ Math.floor(value) }}

      <slider-stubborn
        v-model="value"
        :disabled="disabled"
        :max-thumb-length="thumbLength"
        class="w-full"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { useWindowSize } from '@vueuse/core'
import { computed, ref } from 'vue'
import BaseCheckbox from '../../base-checkbox.vue'
import SliderStubborn from '../slider-stubborn.vue'

const { width, height } = useWindowSize()

const disabled = ref(false)
const value = ref(50)

const thumbLength = computed(() =>
  Math.min(width.value, height.value) / 3,
)
</script>

元件參數

樣式可隨意調整

查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-10 border border-gray-300 p-8">
    <slider-stubborn
      v-model="value"
      disabled
      :max-thumb-length="thumbMaxLength / 4"
      thumb-color="#ff8d36"
      class="z-[999] w-full"
    />

    <slider-stubborn
      v-model="value"
      disabled
      :max-thumb-length="thumbMaxLength / 2"
      :thumb-size="40"
      class="z-[999] w-full"
    />
  </div>
</template>

<script setup lang="ts">
import { useWindowSize } from '@vueuse/core'
import { computed, ref } from 'vue'
import SliderStubborn from '../slider-stubborn.vue'

const { width, height } = useWindowSize()

const value = ref(50)

const thumbMaxLength = computed(() =>
  Math.min(width.value, height.value),
)
</script>

選擇方案

特定範圍停用滑動條,強調停用效果。

選擇喜歡的方案
基本魚缸
1 隻剛剛好
高級池塘
3~6 隻吃飽飽
推薦方案
尊爵大海
任你選!
可選鱈魚數:5
查看範例原始碼
vue
<template>
  <div class="w-full flex flex-col gap-4 py-10">
    <div class="flex flex-col flex-1 justify-center gap-4">
      <div class="text-lg font-bold opacity-90">
        選擇喜歡的方案
      </div>

      <div class="mb-10 flex gap-4">
        <div
          class="card transform rounded-lg from-gray-400 to-gray-500 bg-gradient-to-bl p-1 shadow-md transition-all hover:shadow-lg hover:-translate-y-0.5"
          :class="{ ' border-[0.3rem]': plan === 'basic' }"
          @click="plan = 'basic'"
        >
          <div class="text-lg font-bold md:text-2xl">
            基本魚缸
          </div>

          <div class="mt-1 text-xs opacity-90 md:text-sm">
            1 隻剛剛好
          </div>
        </div>

        <div
          class="card transform border-2 border-indigo-200 rounded-lg from-blue-400 to-indigo-500 bg-gradient-to-bl p-1 shadow-lg transition-all hover:shadow-xl hover:-translate-y-1"
          :class="{ ' border-[0.3rem]': plan === 'premium' }"
          @click="plan = 'premium'"
        >
          <div class="text-lg font-bold md:text-2xl">
            高級池塘
          </div>

          <div class="mt-1 text-xs opacity-90 md:text-sm">
            3~6 隻吃飽飽
          </div>

          <div
            class="absolute right-0 top-0 translate-x-2 transform rounded-bl-lg rounded-tr-lg bg-yellow-400 px-2 py-1 shadow-sm -translate-y-2"
          >
            <div class="text-xs text-red-900 font-semibold md:text-sm">
              推薦方案
            </div>
          </div>
        </div>

        <div
          class="card transform border-2 border-pink-200 rounded-lg from-purple-500 to-pink-500 bg-gradient-to-bl p-1 shadow-xl transition-all hover:shadow-2xl hover:-translate-y-1.5"
          :class="{ ' border-[0.3rem]': plan === 'luxury' }"
          @click="plan = 'luxury'"
        >
          <div class="text-lg font-bold md:text-2xl">
            尊爵大海
          </div>

          <div class="mt-1 text-xs opacity-90 md:text-sm">
            任你選!
          </div>
        </div>
      </div>

      <div class="text-lg font-bold opacity-90">
        可選鱈魚數:{{ Math.floor(sliderValue) }}
      </div>

      <slider-stubborn
        v-model="sliderValue"
        v-bind="disabledParams"
        :min="0"
        :max="10"
        :step="0.1"
        :max-thumb-length="thumbLength"
        :thumb-size="40"
        class="w-full py-4"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import type { ExtractComponentProps } from '../../../types'
import { useWindowSize } from '@vueuse/core'
import { pipe } from 'remeda'
import { computed, ref } from 'vue'
import SliderStubborn from '../slider-stubborn.vue'

type Props = ExtractComponentProps<typeof SliderStubborn>

type Plan = 'basic' | 'premium' | 'luxury'

const { width, height } = useWindowSize()

const plan = ref<Plan>('premium')
const sliderValue = ref(5)

const planRangleMap: Record<Plan, [number, number]> = {
  basic: [1, 1],
  premium: [3, 6],
  luxury: [-1, 11],
}
const disabledParams = computed<
  Pick<Props, 'minDisabled' | 'maxDisabled'>
>(() => pipe(
  planRangleMap[plan.value],
  ([min, max]) => ({
    minDisabled: min,
    maxDisabled: max,
  }),
))

const thumbLength = computed(() =>
  Math.min(width.value, height.value) / 3,
)
</script>

<style lang="sass" scoped>
.card
  display: flex
  flex-direction: column
  justify-content: center
  align-items: center
  aspect-ratio: 1 / 1.3
  flex: 1
  transition-duration: 200ms
  color: white
  cursor: pointer
</style>

原理

使用 svg path 實現拉長與彎曲彈性效果。

注意!Σ(ˊДˋ;)

請不要將 overflow 設定為 hidden,否則握把拉長時會被裁切

原始碼

API

Props

interface Props {
  modelValue: number;
  disabled?: boolean;
  /** 小於此數值也會有 disabled 效果 */
  minDisabled?: number;
  /** 大於此數值也會有 disabled 效果 */
  maxDisabled?: number;
  min?: number;
  max?: number;
  step?: number;
  /** 握把被拉長的最大長度 */
  maxThumbLength?: number;
  thumbSize?: number;
  thumbColor?: string;
  trackClass?: string;
}

Emits

const emit = defineEmits<{
  'update:modelValue': [value: Props['modelValue']];
}>()

v0.32.3