Skip to content

滑动输入条 Slider ​

赞助

滑动型输入器,展示当前值和可选范围

何时使用 ​

  • 当用户需要在数值区间/自定义区间内进行选择时

基本使用 ​

20
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const singleValue = ref<number>(20)
watchEffect(() => {
  console.log('singleValue', singleValue.value)
})
function onChange(value: number | number[]) {
  console.log('change', value)
}
</script>
<template>
  <Slider v-model:value="singleValue" @change="onChange" />
</template>

双滑块 ​

20
80
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const doubleValue = ref<number[]>([20, 80])
watchEffect(() => {
  console.log('doubleValue', doubleValue.value)
})
function onChange(value: number | number[]) {
  console.log('change', value)
}
</script>
<template>
  <Slider range v-model:value="doubleValue" @change="onChange" />
</template>

禁用 ​

20
20
80
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
const disabledSingleValue = ref<number>(20)
const disabledDoubleValue = ref<number[]>([20, 80])
</script>
<template>
  <Flex vertical gap="large">
    <Slider v-model:value="disabledSingleValue" disabled />
    <Slider v-model:value="disabledDoubleValue" range disabled />
  </Flex>
</template>

自定义数值范围 ​

0
-5
5
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const customScaleSingleValue = ref<number>(0)
const customScaleDoubleValue = ref<number[]>([-5, 5])
watchEffect(() => {
  console.log('customScaleSingleValue', customScaleSingleValue.value)
})
watchEffect(() => {
  console.log('customScaleDoubleValue', customScaleDoubleValue.value)
})
</script>
<template>
  <Flex vertical gap="large">
    <Slider :min="-10" :max="10" v-model:value="customScaleSingleValue" />
    <Slider :min="-10" :max="10" range v-model:value="customScaleDoubleValue" />
  </Flex>
</template>

自定义步长 ​

30
30
60
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const customStepSingleValue = ref<number>(30)
const customStepDoubleValue = ref<number[]>([30, 60])
watchEffect(() => {
  console.log('customStepSingleValue', customStepSingleValue.value)
})
watchEffect(() => {
  console.log('customStepDoubleValue', customStepDoubleValue.value)
})
</script>
<template>
  <Flex vertical gap="large">
    <Slider :step="5" v-model:value="customStepSingleValue" />
    <Slider range :step="5" v-model:value="customStepDoubleValue" />
  </Flex>
</template>

自定义刻度标记 ​

使用 marks 属性可以添加刻度标记


0°C26°C37°C100°C
37
0°C26°C37°C100°C
20
65

同时设置 marks & step 属性


0°C26°C37°C
37
0°C26°C37°C
30
60

设置 step 为 'mark',此时 Slider 的可选值仅有 marks 标记的部分


0°C26°C37°C100°C
37
0°C26°C37°C100°C
26
37
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
import { FireFilled } from '@ant-design/icons-vue'
import type { SliderMarks } from 'vue-amazing-ui'
const markSingleValue1 = ref<number>(37)
const markSingleValue2 = ref<number>(37)
const markSingleValue3 = ref<number>(37)
const markDoubleValue1 = ref<number[]>([20, 65])
const markDoubleValue2 = ref<number[]>([30, 60])
const markDoubleValue3 = ref<number[]>([26, 37])
const marks = ref<SliderMarks>({
  0: '0°C',
  26: '26°C',
  37: '37°C',
  100: {
    style: {
      color: '#f50'
    },
    label: '100°C'
  }
})
watchEffect(() => {
  console.log('markSingleValue1', markSingleValue1.value)
})
watchEffect(() => {
  console.log('markSingleValue2', markSingleValue2.value)
})
watchEffect(() => {
  console.log('markSingleValue3', markSingleValue3.value)
})
watchEffect(() => {
  console.log('markDoubleValue1', markDoubleValue1.value)
})
watchEffect(() => {
  console.log('markDoubleValue2', markDoubleValue2.value)
})
watchEffect(() => {
  console.log('markDoubleValue3', markDoubleValue3.value)
})
</script>
<template>
  <p class="mb10">使用 <code>marks</code> 属性可以添加刻度标记</p>
  <Flex vertical>
    <Slider v-model:value="markSingleValue1" :marks="marks">
      <template #mark="{ label, value }">
        <template v-if="value === 100">
          <strong>{{ label }}</strong>
        </template>
        <template v-else>{{ label }}</template>
      </template>
    </Slider>
    <Slider range v-model:value="markDoubleValue1" :marks="marks">
      <template #mark="{ label, value }">
        <template v-if="value === 100">
          <strong>{{ label }}</strong>
        </template>
        <template v-else>{{ label }}</template>
      </template>
    </Slider>
  </Flex>
  <p class="mb10">同时设置 <code>marks</code> & <code>step</code> 属性</p>
  <Flex vertical>
    <Slider v-model:value="markSingleValue2" :marks="marks" :step="10">
      <template #mark="{ label, value }">
        <template v-if="value === 100">
          <FireFilled />
        </template>
        <template v-else>{{ label }}</template>
      </template>
    </Slider>
    <Slider range v-model:value="markDoubleValue2" :marks="marks" :step="10">
      <template #mark="{ label, value }">
        <template v-if="value === 100">
          <FireFilled />
        </template>
        <template v-else>{{ label }}</template>
      </template>
    </Slider>
  </Flex>
  <p class="mb10">设置 <code>step</code> 为 <code>'mark'</code>,此时 <code>Slider</code> 的可选值仅有 <code>marks</code> 标记的部分</p>
  <Flex vertical>
    <Slider v-model:value="markSingleValue3" :marks="marks" step="mark">
      <template #mark="{ label, value }">
        <template v-if="value === 100">
          <strong>{{ label }}</strong>
        </template>
        <template v-else>{{ label }}</template>
      </template>
    </Slider>
    <Slider range v-model:value="markDoubleValue3" :marks="marks" step="mark">
      <template #mark="{ label, value }">
        <template v-if="value === 100">
          <strong>{{ label }}</strong>
        </template>
        <template v-else>{{ label }}</template>
      </template>
    </Slider>
  </Flex>
</template>

垂直模式 ​

37
20
80
0°C26°C37°C100°C
37
0°C26°C37°C100°C
20
65
0°C26°C37°C
30
60
0°C26°C37°C100°C
26
37
Show Code
vue
<script setup lang="ts">
import { ref, h, watchEffect, isVNode } from 'vue'
import { FireFilled } from '@ant-design/icons-vue'
import type { SliderMarks } from 'vue-amazing-ui'
const verticalSingleValue = ref<number>(37)
const verticalDoubleValue = ref<number[]>([20, 80])
const markVerticalSingleValue = ref<number>(37)
const markVerticalDoubleValue1 = ref<number[]>([20, 65])
const markVerticalDoubleValue2 = ref<number[]>([30, 60])
const markVerticalDoubleValue3 = ref<number[]>([26, 37])
const marks = ref<SliderMarks>({
  0: '0°C',
  26: '26°C',
  37: '37°C',
  100: {
    style: {
      color: '#f50'
    },
    label: '100°C'
  }
})
const verticalMarks = ref<SliderMarks>({
  0: '0°C',
  26: '26°C',
  37: '37°C',
  100: {
    style: {
      color: '#f50',
      fontWeight: 'bold'
    },
    label: h(FireFilled)
  }
})
watchEffect(() => {
  console.log('verticalSingleValue', verticalSingleValue.value)
})
watchEffect(() => {
  console.log('verticalDoubleValue', verticalDoubleValue.value)
})
watchEffect(() => {
  console.log('markVerticalSingleValue', markVerticalSingleValue.value)
})
watchEffect(() => {
  console.log('markVerticalDoubleValue1', markVerticalDoubleValue1.value)
})
watchEffect(() => {
  console.log('markVerticalDoubleValue2', markVerticalDoubleValue2.value)
})
watchEffect(() => {
  console.log('markVerticalDoubleValue3', markVerticalDoubleValue3.value)
})
</script>
<template>
  <Space :gap="36" style="height: 300px">
    <Slider vertical v-model:value="verticalSingleValue" />
    <Slider range vertical v-model:value="verticalDoubleValue" />
    <Slider vertical v-model:value="markVerticalSingleValue" :marks="marks" />
    <Slider vertical range v-model:value="markVerticalDoubleValue1" :marks="marks" />
    <Slider vertical range v-model:value="markVerticalDoubleValue2" :marks="verticalMarks" :step="10" />
    <Slider vertical range v-model:value="markVerticalDoubleValue3" :marks="verticalMarks" step="mark">
      <template #mark="{ label, value }">
        <template v-if="isVNode(label)"> {{ value }}°C </template>
        <template v-else>{{ label }}</template>
      </template>
    </Slider>
  </Space>
</template>

带输入框的滑块 ​

20
0.5
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const inputSingleValue = ref<number>(20)
const smallSingleValue = ref<number>(0.5)
watchEffect(() => {
  console.log('inputSingleValue', inputSingleValue.value)
})
watchEffect(() => {
  console.log('smallSingleValue', smallSingleValue.value)
})
</script>
<template>
  <Row :gutter="[24, 16]">
    <Col :span="18">
      <Slider v-model:value="inputSingleValue" />
    </Col>
    <Col :span="6">
      <InputNumber v-model:value="inputSingleValue" :min="0" :max="100" />
    </Col>
    <Col :span="18">
      <Slider v-model:value="smallSingleValue" :min="0" :max="1" :step="0.01" />
    </Col>
    <Col :span="6">
      <InputNumber v-model:value="smallSingleValue" :min="0" :max="1" :step="0.01" />
    </Col>
  </Row>
</template>

格式化 tooltip ​

20%
20%
80%
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const formatSingleValue = ref<number>(20)
const formatDoubleValue = ref<number[]>([20, 80])
watchEffect(() => {
  console.log('formatSingleValue', formatSingleValue.value)
})
watchEffect(() => {
  console.log('formatDoubleValue', formatDoubleValue.value)
})
function formatter(value: number) {
  return `${value}%`
}
</script>
<template>
  <Flex vertical gap="large">
    <Slider :format-tooltip="formatter" v-model:value="formatSingleValue" />
    <Slider range :format-tooltip="formatter" v-model:value="formatDoubleValue" />
  </Flex>
</template>

隐藏 tooltip ​

Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const hideTooltipSingleValue = ref<number>(20)
const hideTooltipDoubleValue = ref<number[]>([20, 80])
watchEffect(() => {
  console.log('hideTooltipSingleValue', hideTooltipSingleValue.value)
})
watchEffect(() => {
  console.log('hideTooltipDoubleValue', hideTooltipDoubleValue.value)
})
</script>
<template>
  <Flex vertical gap="large">
    <Slider :tooltip="false" v-model:value="hideTooltipSingleValue" />
    <Slider range :tooltip="false" v-model:value="hideTooltipDoubleValue" />
  </Flex>
</template>

始终显示 Tooltip ​

20
20
80
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const tooltipOpenSingleValue = ref<number>(20)
const tooltipOpenDoubleValue = ref<number[]>([20, 80])
watchEffect(() => {
  console.log('tooltipOpenSingleValue', tooltipOpenSingleValue.value)
})
watchEffect(() => {
  console.log('tooltipOpenDoubleValue', tooltipOpenDoubleValue.value)
})
</script>
<template>
  <Flex vertical :gap="36">
    <Slider tooltip-open v-model:value="tooltipOpenSingleValue" />
    <Slider range tooltip-open v-model:value="tooltipOpenDoubleValue" />
  </Flex>
</template>

自定义 Tooltip 位置 ​

默认水平模式在滑块上方、垂直模式在滑块右侧,可用 tooltipPlacement 指定为四个方向之一;若该方向空间不足会自动翻转到对侧

20
20
80
80
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
const placementTopValue = ref<number>(20)
const placementBottomValue = ref<number>(80)
const placementLeftValue = ref<number>(20)
const placementRightValue = ref<number>(80)
</script>
<template>
  <div class="placement-rect">
    <Slider :width="488" tooltip-placement="top" v-model:value="placementTopValue" />
    <div class="rect-body">
      <Slider vertical :height="120" tooltip-placement="left" v-model:value="placementLeftValue" />
      <Slider vertical :height="120" tooltip-placement="right" v-model:value="placementRightValue" />
    </div>
    <Slider :width="488" tooltip-placement="bottom" v-model:value="placementBottomValue" />
  </div>
</template>
<style lang="less" scoped>
/* 四条 Slider 围成大致矩形:上 / 下为水平条(气泡朝上 / 朝下),左 / 右为竖直条(气泡朝左 / 朝右)。
   水平条取 488px(容器 520 减去两侧竖直条各 16px),两端即落在两侧轨道线上,不追求严格首尾相接 */
.placement-rect {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 520px;
  /* 左对齐到内容区(不用 auto 居中);左缩进 64px = 朝左气泡的最小空间(气泡约 40px + 16px 间距),
     否则 left 方向会被定位内核翻转到右侧;上下留白:上方 40px 容气泡,下方不额外留 */
  margin: 40px 0 0 64px;
}
.rect-body {
  display: flex;
  justify-content: space-between;
  width: 100%;
}
</style>

自定义 Tooltip 内容 ​

通过 tooltip 插槽自定义气泡内容(value 为格式化后的当前值),配合 tooltipClass 用外部样式类定制外观

37 °C
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
const customTooltipValue = ref<number>(37)
</script>
<template>
  <Slider v-model:value="customTooltipValue" tooltip-class="custom-slider-tooltip">
    <template #tooltip="{ value }">
      <strong>{{ value }}</strong> °C
    </template>
  </Slider>
</template>
<style lang="less">
.custom-slider-tooltip {
  border: 1px solid #ff6900;
  strong {
    font-size: 20px;
    font-weight: 600;
  }
}
</style>

自定义样式 ​

通过修改样式变量可以自定义滑动输入条样式、标记样式、Tooltip 样式

20
0°C26°C37°C100°C
20
80
Show Code
vue
<script setup lang="ts">
import { ref, watchEffect } from 'vue'
const customStyleSingleValue = ref<number>(20)
const customStyleDoubleValue = ref<number[]>([20, 80])
const singleCustomStyle = {
  '--slider-track-color': '#ffbb96',
  '--slider-track-color-hover': '#d4380d',
  '--slider-handle-color': '#fff2e8',
  '--slider-handle-shadow-color': '#ffbb96',
  '--slider-handle-shadow-color-hover-focus': '#d4380d',
  '--slider-tooltip-color': 'rgba(0, 0, 0, 0.88)',
  '--slider-tooltip-bg-color': '#fff'
}
const rangeCustomStyle = {
  '--slider-rail-color': 'rgb(219, 219, 223)',
  '--slider-rail-color-hover': 'rgb(199, 199, 203)',
  '--slider-track-color': '#ffbb96',
  '--slider-track-color-hover': '#d4380d',
  '--slider-handle-color': '#fff2e8',
  '--slider-handle-shadow-color': '#ffbb96',
  '--slider-handle-shadow-color-hover-focus': '#d4380d',
  '--slider-dot-border-color': 'rgb(219, 219, 223)',
  '--slider-dot-border-color-hover': 'rgb(199, 199, 203)',
  '--slider-dot-color-active': '#ffbb96',
  '--slider-tooltip-color': 'rgba(0, 0, 0, 0.88)',
  '--slider-tooltip-bg-color': '#fff'
}
const tooltipStyle = {
  top: '-20px',
  fontSize: '16px',
  fontWeight: 500,
  lineHeight: 1.5,
  height: '40px',
  padding: '8px 12px',
  borderRadius: '8px'
}
watchEffect(() => {
  console.log('customStyleSingleValue', customStyleSingleValue.value)
})
watchEffect(() => {
  console.log('customStyleDoubleValue', customStyleDoubleValue.value)
})
</script>
<template>
  <Flex vertical gap="large">
    <Slider :style="singleCustomStyle" v-model:value="customStyleSingleValue" />
    <Slider :style="rangeCustomStyle" range v-model:value="customStyleDoubleValue" :marks="marks" :tooltip-style="tooltipStyle" />
  </Flex>
</template>

APIs ​

Slider ​

参数说明类型默认值
width滑动输入条宽度,单位 px,水平模式时生效string | number'100%'
height滑动输入条高度,单位 px,垂直模式时生效string | number'100%'
vertical是否启用垂直模式booleanfalse
min最小值number0
max最大值number100
marks刻度标记,key 的类型必须为 number 且取值在闭区间 [min, max] 内,每个标记可以单独设置样式SliderMarks{}
disabled是否禁用booleanfalse
range是否使用双滑块模式booleanfalse
step步长,取值必须大于 0,并且可被 (max - min) 整除;当 marks 不为空对象时,可以设置 step 为 'mark',此时 Slider 的可选值仅有 marks 标记的部分number | 'mark'1
tooltip是否展示 Tooltipbooleantrue
tooltipOpen是否一直显示 tooltipbooleanfalse
tooltipStyle自定义 Tooltip 样式CSSProperties{}
tooltipClass自定义 Tooltip 类名string-
tooltipPlacementTooltip 弹出位置,默认为水平模式 top、垂直模式 right'top' | 'bottom' | 'left' | 'right'-
formatTooltipSlider 会把当前值传给 formatTooltip,并在 Tooltip 中显示 formatTooltip 的返回值(value: number) => string | number(value: number) => value
value
v-model
设置当前取值,range 为 false 时为单个值,否则为区间值number | number[]0

Marks Type ​

名称值
Marks{ [markValue: number]: string | VNode | (() => VNode) | { style: CSSProperties, label: string | VNode | (() => VNode) } }

Slots ​

名称说明用法
mark自定义刻度标记v-slot:mark="{ label, value }"
tooltip自定义 Tooltip 内容,value 为格式化后的当前值v-slot:tooltip="{ value }"

Events ​

名称说明类型
change当前取值变化后的回调(value: number | number[]) => void

Released under the MIT License.