这是一款简单易用的 Slider Bar,原生 HTML + CSS + JS 编写, 亲测兼容 Chrome, Firefox, IE 9+ , 欢迎一起探讨、交流。
引用
<link rel="stylesheet" type="text/css" href="./index.css">
<div id="slider"></div>
<script type="text/javascript" src="./index.js"></script>
<script type="text/javascript">
var sb = new EasySliderBar({
el: 'slider'
})
</script>
参数
Name | Type | Constraint | Comment |
---|---|---|---|
el | String | required | 容器节点 |
max | Number | default 100 | 上限 |
min | Number | default 0 | 下限 |
scale | Integer | default 0 | 小数位数 |
trackHeight | Integer | default 10 | 轨道高度 |
type | enum['circle', 'square', 'diamond'] | default 'circle' | slider bar类型 |
barNumber | Integer | default 1 | slider bar数量 |
positions | Array | default [min...] | slider bar初始位置 |
- 当参数 el 非法,slider bar 取消创建
- 当其他参数非法,取默认值
方法
Name | Parameter | Return | Comment |
---|---|---|---|
setBarPosition | pos, index | void | 设置 index 指定的 slider bar 的位置为 pos,如果index === undefined,则设置所有 slider bar 的位置为 pos |
getBarPosition | index | Number Array | 获取 index 指定的 slide rbar 的位置,如果index === undefined,则返回所有 slider bar 的位置数组 |
源码
index.js
/**
* Created by lonelydawn on 2017-11-20.
* EasySliderBar - Easy slider bar
*/
// Polyfill
Array.prototype.forEach = Array.prototype.forEach || function (cb) {
for (var i = 0; i < this.length; i++) {
cb(this[i], i)
}
}
Array.prototype.filter = Array.prototype.filter || function (cb) {
var arr = []
for (var i = 0; i < this.length; i++) {
if (cb[this[i], i]) {
arr.push(this[i])
}
}
return arr
}
var EasySliderBar = function (options) {
// Add class, and return the changed className
var getPushedClass = function (className, value) {
return typeof className === 'string' && typeof value === 'string'
? className.split(' ').concat(value).join(' ') : className
}
// Remove class, and return the changed className
var getRemovedClass = function (className, value) {
if (typeof className === 'string' && typeof value === 'string') {
return className.split(' ').filter(function (item) {
return item !== '' && item !== value
}).join(' ')
}
return className
}
// Get parallel pixel to scale
var getInterval = function () {
return track.clientWidth / (max - min)
}
// Limit bars' moving range
var getValidLeft = function (value) {
if (value < 0) {
return 0
} else if (value > track.clientWidth) {
return track.clientWidth
} else {
return value
}
}
// Add trigger on slidebar
var setBarMove = function (bar, index) {
bar.onmousedown = function (e) {
var start = (e || window.event).clientX
var left = Math.floor((bar.position - min) * getInterval())
bar.label.className = getRemovedClass(bar.label.className, 'hidden')
// Execute callback
onBarMoveBegin({
index: index,
position: Number(bar.position)
})
document.onmousemove = function (e) {
var movingLeft = getValidLeft(left + (e || window.event).clientX - start)
var movingPosition = (min + movingLeft / getInterval()).toFixed(scale)
bar.label.innerHTML = movingPosition
bar.style.left = movingLeft - barOffset + 'px'
onBarMoving({
index: index,
position: Number(movingPosition)
})
}
document.onmouseup = function (e) {
bar.position = (min + getValidLeft(left + (e || window.event).clientX - start) / getInterval()).toFixed(scale)
bar.label.className = getPushedClass(bar.label.className, 'hidden')
// Execute callback
onBarMoveEnd({
index: index,
position: Number(bar.position)
})
document.onmousemove = null
document.onmouseup = null
bar.releaseCapture && bar.releaseCapture()
}
bar.setCapture && bar.setCapture()
return false
}
}
var el = options.el
var scale = options.scale || 0
var min = !isNaN(options.min) ? options.min : 0
var max = !isNaN(options.max) ? (options.max > min ? options.max : min + 100) : 100
var barNumber = options.barNumber || 1
var positions = Object.prototype.toString.call(options.positions) === '[object Array]' ? options.positions : []
for (var i = 0; i < barNumber; i++) {
positions[i] = positions[i] && positions[i] >= min && positions[i] <= max ? positions[i] : min
}
var type = options.type || 'circle'
// Set bars' width and height by type
var trackHeight = !isNaN(options.trackHeight) ? options.trackHeight : 10
var barWidth = {
square: trackHeight * 2,
circle: trackHeight * 3,
diamond: 20
}[type]
var barHeight = {
square: trackHeight * 3,
circle: trackHeight * 3,
diamond: trackHeight
}[type]
var barOffset = barWidth / 2
var labelWidth = (30 + 7 * scale) || 30
var labelOffset = labelWidth / 2 - barOffset
// Get customized callback
var onBarMoveBegin = options.onBarMoveBegin || new Function()
var onBarMoving = options.onBarMoving || new Function()
var onBarMoveEnd = options.onBarMoveEnd || new Function()
var wrapper = document.getElementById(el)
if (!wrapper) {
return
}
// Init wrapper height
wrapper.style.padding = barOffset + 5 + 'px'
wrapper.style.height = trackHeight + 'px'
// Empty container
var childs = wrapper.childNodes
for (var i = childs.length - 1; i > -1; i--) {
wrapper.removeChild(childs[i])
}
// Create track
var track = document.createElement('div')
track.className = 'slider-track'
wrapper.appendChild(track)
// Create slider bar
var barStack = []
for (var counter = 0; counter < barNumber; counter++) {
var bar = document.createElement('div')
bar.className = 'slider-bar ' + type
bar.position = positions[counter]
bar.style.width = barWidth + 'px'
bar.style.height = barHeight + 'px'
bar.style.top = (trackHeight - barHeight) / 2 + 'px'
bar.style.left = Math.floor((positions[counter] - min) * getInterval()) - barOffset + 'px'
setBarMove(bar, counter)
// Create slider bar label
var label = document.createElement('div')
label.className = 'slider-label hidden'
label.style.width = labelWidth + 'px'
label.style.left = -labelOffset + 'px'
label.innerHTML = positions[counter].toFixed(scale)
bar.label = label
// Create DOM structure
bar.appendChild(label)
track.appendChild(bar)
barStack.push(bar)
}
return {
// Set some bars' position. (If index is not defined, set all.)
setBarPosition: function (pos, index) {
var set = function (bar) {
if (pos >= min && pos <= max) {
bar.position = pos
bar.style.left = Math.floor((pos - min) * getInterval()) - barOffset + 'px'
bar.label.innerHTML = Number(pos).toFixed(scale)
}
}
index ? set(barStack[index]) : barStack.forEach(function (item) {
set(item)
})
},
// Return some bars' position. (If index is not defined, return all.)
getBarPosition: function (index) {
return index >= 0 ? barStack[index].position : barStack.map(function (item) {
return item.position
})
}
}
}
index.css
.slider-track {
width: 100%;
height: 100%;
position: relative;
border-radius: 100px;
font-family: Roboto;
background-color: #e4e7ed;
}
.slider-label {
padding: 3px 0;
position: absolute;
top: -40px;
color: #fff;
font-size: 12px;
text-align: center;
border-radius: 5px;
background-color: #303133;
transition: all 300ms linear;
}
.slider-label:after {
width: 0px;
height: 0px;
border: 6px transparent solid;
border-top-color: #303133;
position:absolute;
top: 100%;
left: calc(50% - 6px);
content:""
}
.slider-label.hidden {
display: none;
}
.slider-bar {
position: absolute;
box-sizing: border-box;
}
.slider-bar:hover .slider-label {
display: block;
}
.slider-bar.circle,
.slider-bar.square {
border: 2px solid #409EFF;
background-color: #FFF;
}
.slider-bar.circle {
border-radius: 50%;
}
.slider-bar.square {
border-radius: 3px;
}
.slider-bar.diamond {
background-color: #409EFF;
}
.slider-bar.diamond:before {
width: 0px;
height: 0px;
border: 10px transparent solid;
border-bottom-color: #409EFF;
position:absolute;
bottom: 100%;
left: 0;
content:""
}
.slider-bar.diamond:after{
width: 0px;
height: 0px;
border: 10px transparent solid;
border-top-color: #409EFF;
position:absolute;
top: 100%;
left: 0;
content:""
}
源码奉上,任君 Hack 。