组件介绍
“Slider” 组件是一种常见的用户界面元素,通常用于允许用户在一个范围内选择一个数值或数值范围。用户可以通过拖动滑块来选择值,这种组件通常用于调整设置、选择价格范围、音量控制、时间选择等。以下是关于 “Slider” 组件的介绍和特点:
-
滑块:
- “Slider” 组件通常包括一个或多个滑块,用户可以通过拖动滑块来选择数值。
-
数值范围:
- “Slider” 允许用户在一个预定义的数值范围内选择值,通常包括最小值和最大值。
-
单一和范围选择:
- “Slider” 组件可以是单一滑块,用于选择单个值,也可以是范围滑块,用于选择一个范围,例如选择一个起始值和结束值。
-
步长和刻度:
- “Slider” 组件通常支持设置步长,也就是滑块每次拖动时数值的变化量。它们还可以包括刻度标记,以帮助用户更容易地选择数值。
-
标签和数值显示:
- “Slider” 组件通常包括标签或数值显示区域,用于显示当前选择的值或范围。
-
自定义样式:
- 开发人员通常可以自定义 “Slider” 组件的样式,包括滑块的外观、颜色、尺寸等。
-
事件处理:
- “Slider” 组件通常支持事件处理,开发人员可以监听用户的滑动操作,并在数值变化时执行自定义操作。
-
垂直和水平方向:
- “Slider” 组件可以水平或垂直方向展示,具体取决于设计需求。一些应用程序中可能需要垂直滑块,例如音量控制。
-
响应式设计:
- “Slider” 组件通常支持响应式设计,以适应不同屏幕尺寸和设备类型。
-
可访问性:
- 良好的 “Slider” 组件应该考虑到可访问性,以确保它对于使用辅助技术的用户也是可访问的。
“Slider” 组件对于用户交互和选择数值范围非常有用。它们通常用于网页应用程序、移动应用程序和桌面应用程序中,提供了一种用户友好的方式来选择值或范围,以满足不同的应用需求。许多前端框架和库提供了 “Slider” 组件的实现,或者你可以自行编写代码来创建适合你应用程序需求的滑块功能。
css改变html原生的slider组件
在前端开发中,Slider组件可以使用HTML、CSS和JavaScript实现。HTML中可以使用range input元素来创建Slider组件,CSS可以控制Slider组件的样式,而JavaScript可以增加Slider组件的交互功能,例如拖动滑块时更新滑块位置以及相应的值。
<input type="range" id="slider-input" min="0" max="100" />
// 修改滑条的轨道样式
input[type='range'] {
-webkit-appearance: none;
background: linear-gradient(75deg, #fff, #ff2d52);
border-radius: 4px;
width: 100%;
height: 12px;
outline: none;
// box-shadow: 0 0 6px rgba();
}
// 修改滑条的按钮样式
input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
background: #f53b57;
border-radius: 50%;
transition: 0.3s;
cursor: pointer;
}
// 修改滑条按钮激活时的样式
input[type='range']:active::-webkit-slider-thumb {
background: #f53b57;
box-shadow: 0 0 0 6px rgba(155, 73, 146, 0.4);
}
如果想要存手写一个slider组件,我们需要准备些什么
- slider组件需要确立一个数值范围,即最大最小值min或max
- 按钮的拖动时,触发事件监听,和数值变化
- step步长的限制
- 最难处理的是 进度与value与min和max之间及step的关联计算
- 按钮的拖动效果,以及拖动的边界限制
- 点击滑条上某个位置时,按钮和数值的变化
- 滑条的禁用
组件安装与使用
需要先安装vue3-dxui
yarn add vue3-dxui
或者
npm install vue3-dxui
全局main.ts中引入css
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import 'vue3-dxui/dxui/dxui.css'
createApp(App).use(store).use(router).mount('#app')
按需引入
<script>
import { Slider } from 'vue3-dxui'
export default {
components: {
Slider
}
}
</script>
组件代码
<template>
<div class="dx-slider-warpper">
<div class="dx-slider-content" :draggable="false">
<div class="dx-slider-track" ref="sliderTrack" :draggable="false" @click="handleClickTrack">
<div class="dx-slider-fill" :style="{ width: sliderFillPercent + '%' }"></div>
</div>
<div
class="dx-slider-thumb"
:class="sliderThumbStatusClass"
ref="sliderThumb"
:style="{ left: thumbX }"
@mousedown="thumbDown"
:draggable="false"
></div>
</div>
<div class="dx-slider-other">
<div class="dx-slider-min">{{ min }}</div>
<div class="dx-slider-value">{{ sliderValue }}</div>
<div class="dx-slider-max">{{ max }}</div>
</div>
</div>
</template>
<script lang="ts">
import { onMounted, ref, watch, SetupContext } from 'vue'
import { Data } from './types/index'
export default {
props: {
// 滑动条最小值
min: {
require: false,
default: 0,
type: Number
},
// 滑动条最大值
max: {
require: false,
default: 100,
type: Number
},
// 滑动条每一次滑动的最小值1 必须为整数
step: {
require: false,
default: 1,
type: Number
},
value: {
require: false,
default: 0,
type: Number
},
disabled: {
require: false,
default: false,
type: Boolean
}
},
setup(props: Data, context: SetupContext) {
let maxX = 0
let thumbWidth = 6
const sliderTrack = ref<any>()
const sliderThumb = ref<any>()
// sliderThumb被激活时的样式名称
const sliderThumbStatusClass = ref('')
// 当前的值
const sliderValue = ref<number>(props.value as number)
// 进度条填充百分比
const sliderFillPercent = ref<number>(0)
// 数值之间的间距
const distance = Number(props.max) - Number(props.min)
// value的值必须大于等于min,小于等于max
if (sliderValue.value < Number(props.min)) {
sliderValue.value = Number(props.min) || 0
} else if (sliderValue.value > Number(props.max)) {
sliderValue.value = Number(props.max) || 100
}
const thumbX = ref('0px')
const thumbTop = ref('-7px')
onMounted(() => {
thumbWidth = (sliderThumb.value?.offsetWidth || 0) / 2
thumbTop.value = -((sliderThumb.value?.offsetHeight || 0) / 2) + 'px'
maxX = (sliderTrack.value?.offsetWidth || 0) - thumbWidth
// 初始化,根据sliderValue.value的值,分别计算百分比和thumbX
sliderFillPercent.value = ((sliderValue.value - Number(props.min)) / distance) * 100
thumbX.value =
((sliderValue.value - Number(props.min)) / distance) * (maxX + thumbWidth) -
thumbWidth +
'px'
if (props.disabled) {
sliderThumbStatusClass.value = 'dx-slider-thumb-disabled'
}
})
// 点击轨道,thumb跳跃至点击的位置,offsetX是个好东西
const handleClickTrack = (e: any) => {
const targetX = e?.offsetX
if (props.disabled) {
return
}
thumbX.value = targetX - thumbWidth + 'px'
}
const thumbDown = (e: any) => {
if (props.disabled) {
return
}
sliderThumbStatusClass.value = 'dx-slider-thumb-active'
const startX = e?.clientX
const initX = parseFloat(thumbX.value)
const handler = (event: any) => {
const nowX = event.clientX
const disX = nowX - startX
thumbX.value = initX + disX + 'px'
// 限制可拖拽的范围
if (initX + disX <= -thumbWidth) {
thumbX.value = `-${thumbWidth}px`
}
if (initX + disX > maxX) {
thumbX.value = `${maxX}px`
}
}
document.addEventListener('mousemove', handler, false)
document.addEventListener(
'mouseup',
() => {
sliderThumbStatusClass.value = ''
document.removeEventListener('mousemove', handler)
},
false
)
}
watch(thumbX, () => {
// 计算百分比,显示fill的进度条
sliderFillPercent.value =
((parseFloat(thumbX.value) + thumbWidth) / (maxX + thumbWidth)) * 100
// 计算对应的value的值
const b =
((parseFloat(thumbX.value) + thumbWidth) / (maxX + thumbWidth)) * distance +
Number(props.min)
// 求余并去除余数
const a = b % Number(props.step)
sliderValue.value = b - a
context.emit('sliderChange', sliderValue.value)
})
return {
thumbDown,
thumbX,
thumbTop,
handleClickTrack,
sliderTrack,
sliderThumb,
sliderFillPercent,
sliderThumbStatusClass,
sliderValue
}
}
}
</script>
<style lang="scss" scoped>
@import '@/scss/layout.scss';
.dx-slider-warpper {
// .dx-slider-min,
// .dx-slider-max {
// display: inline-block;
// }
.dx-slider-other {
// overflow: hidden;
margin: 6px 0;
position: relative;
// &::after {
// content: '';
// clear: both;
// display: block;
// }
.dx-slider-min {
position: absolute;
transform: translateX(-50%);
}
.dx-slider-max {
position: absolute;
right: 0;
top: 0;
transform: translateX(50%);
}
}
.dx-slider-value {
display: inline-block;
margin-left: 50%;
transform: translateX(-50%);
}
.dx-slider-content {
position: relative;
cursor: pointer;
-webkit-user-drag: none;
user-select: none;
width: calc(100%);
}
.dx-slider-track {
width: 100%;
height: 6px;
border-radius: 3px;
background-color: $background-color;
overflow: hidden;
.dx-slider-fill {
background-color: $blue-middle-color;
height: 100%;
width: 20%;
}
}
.dx-slider-track:hover {
background: #e1e1e1;
}
.dx-slider-thumb {
height: 14px;
width: 14px;
border-radius: 50%;
border: 2px solid $blue-color;
background: $white-color;
cursor: pointer;
position: absolute;
z-index: 100;
top: 50%;
transform: translateY(-50%);
}
.dx-slider-thumb-active {
height: 20px;
width: 20px;
}
.dx-slider-thumb-disabled {
cursor: not-allowed;
border: 2px solid $background-color;
background: $white-color;
}
}
</style>
参数说明
参数 | 说明 |
---|---|
max | 最大值 number 默认值 0 |
min | 最小值 number 默认值 0 |
step | 步长 number 必须为整数 最小为1 默认值 1 |
value | 滑条当前的值 |
disabled | 是否禁用滑条 |
事件
事件名称 | 说明 |
---|---|
sliderChange | 通过@sliderChange 监听滑条的变化和最新的值 |
关于dxui组件库
dxui组件库是我个人搭建的vue3 前端交互组件库,倾向于pc网站的交互模式。
- 如果你有任何问题,请在博客下方评论留言,我尽可能24小时内回复。
- dxui新上线的官网域名变更 http://dxui.cn
- npm 官方链接 https://www.npmjs.com/package/vue3-dxui
- 如果你想看完整源码 https://github.com/757363985/dxui