<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>jQuery可拖动控制进度条</title>
<style type="text/css">
.demo {
width: 350px;
margin: 100px auto 10px auto
}
#g1,
#g2 {
margin-top: 50px
}
</style>
<link rel="stylesheet" href="css/jquery.range.css" />
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.range.js"></script>
<script type="text/javascript">
$(function() {
$('.single-slider').jRange({
from: 0,
to: 10,
step: 1,
width: 200,
showLabels: true,
showScale: true
});

});
</script>
</head>
<body>
<div class="demo">
<input type="hidden" class="single-slider" value="5" />
</div>
</body>
</html>

css

.slider-container .back-bar {
height: 10px;
position: relative;
}

.slider-container .back-bar .selected-bar {
position: absolute;
height: 100%;
}

.slider-container .back-bar .pointer {
position: absolute;
width: 10px;
height: 10px;
background-color: red;
cursor: col-resize;
opacity: 1;
z-index: 2;
}

.slider-container .back-bar .pointer-label {
position: absolute;
top: -17px;
font-size: 8px;
background: white;
white-space: nowrap;
line-height: 1;
}

.slider-container .back-bar .focused {
z-index: 10;
}

.slider-container .scale {
top: 2px;
position: relative;
}

.slider-container .scale span {
position: absolute;
height: 5px;
border-left: 1px solid #999;
font-size: 0;
}

.slider-container .scale ins {
font-size: 9px;
text-decoration: none;
position: absolute;
left: 0;
top: 5px;
color: #999;
line-height: 1;
}

.theme-green .back-bar {
height: 15px;
border-radius: 2px;
background-color: #eeeeee;
background-color: #e7e7e7;
}

.theme-green .back-bar .selected-bar {
border-radius: 2px;
background-color: #a1fad0;
}

.theme-green .back-bar .pointer {
width: 14px;
height: 25px;
top: -5px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
background-color: #e7e7e7;
}

jquery.range.js

/*jshint multistr:true, curly: false */
/*global jQuery:false, define: false */
/**
* jRange - Awesome range control
*
* Written by
* ----------
* Nitin Hayaran (nitinhayaran@gmail.com)
*
* Licensed under the MIT (MIT-LICENSE.txt).
*
* @author Nitin Hayaran
* @version 0.1-RELEASE
*
* Dependencies
* ------------
* jQuery (http://jquery.com)
*
**/
;
(function($, window, document, undefined) {
'use strict';

var jRange = function() {
return this.init.apply(this, arguments);
};
jRange.prototype = {
defaults: {
onstatechange: function() {},
isRange: false,
showLabels: true,
showScale: true,
step: 1,
format: '%s',
theme: 'theme-green',
width: 300,
disable: false
},
template: '<div class="slider-container">\
<div class="back-bar">\
<div class="selected-bar"></div>\
<div class="pointer low"></div><div class="pointer-label">123456</div>\
<div class="pointer high"></div><div class="pointer-label">456789</div>\
<div class="clickable-dummy"></div>\
</div>\
<div class="scale"></div>\
</div>',
init: function(node, options) {
this.options = $.extend({}, this.defaults, options);
this.inputNode = $(node);
this.options.value = this.inputNode.val() || (this.options.isRange ? this.options.from + ',' + this.options.from : this.options.from);
this.domNode = $(this.template);
this.domNode.addClass(this.options.theme);
this.inputNode.after(this.domNode);
this.domNode.on('change', this.onChange);
this.pointers = $('.pointer', this.domNode);
this.lowPointer = this.pointers.first();
this.highPointer = this.pointers.last();
this.labels = $('.pointer-label', this.domNode);
this.lowLabel = this.labels.first();
this.highLabel = this.labels.last();
this.scale = $('.scale', this.domNode);
this.bar = $('.selected-bar', this.domNode);
this.clickableBar = this.domNode.find('.clickable-dummy');
this.interval = this.options.to - this.options.from;
this.render();
},
render: function() {
// Check if inputNode is visible, and have some width, so that we can set slider width accordingly.
if (this.inputNode.width() === 0 && !this.options.width) {
console.log('jRange : no width found, returning');
return;
} else {
this.domNode.width(this.options.width || this.inputNode.width());
this.inputNode.hide();
}

if (this.isSingle()) {
this.lowPointer.hide();
this.lowLabel.hide();
}
if (!this.options.showLabels) {
this.labels.hide();
}
this.attachEvents();
if (this.options.showScale) {
this.renderScale();
}
this.setValue(this.options.value);
},
isSingle: function() {
if (typeof(this.options.value) === 'number') {
return true;
}
return (this.options.value.indexOf(',') !== -1 || this.options.isRange) ?
false : true;
},
attachEvents: function() {
this.clickableBar.click($.proxy(this.barClicked, this));
this.pointers.on('mousedown touchstart', $.proxy(this.onDragStart, this));
this.pointers.bind('dragstart', function(event) {
event.preventDefault();
});
},
onDragStart: function(e) {
if ( this.options.disable || (e.type === 'mousedown' && e.which !== 1)) {
return;
}
e.stopPropagation();
e.preventDefault();
var pointer = $(e.target);
this.pointers.removeClass('last-active');
pointer.addClass('focused last-active');
this[(pointer.hasClass('low') ? 'low' : 'high') + 'Label'].addClass('focused');
$(document).on('mousemove.slider touchmove.slider', $.proxy(this.onDrag, this, pointer));
$(document).on('mouseup.slider touchend.slider touchcancel.slider', $.proxy(this.onDragEnd, this));
},
onDrag: function(pointer, e) {
e.stopPropagation();
e.preventDefault();

if (e.originalEvent.touches && e.originalEvent.touches.length) {
e = e.originalEvent.touches[0];
} else if (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length) {
e = e.originalEvent.changedTouches[0];
}

var position = e.clientX - this.domNode.offset().left;
this.domNode.trigger('change', [this, pointer, position]);
},
onDragEnd: function(e) {
this.pointers.removeClass('focused');
this.labels.removeClass('focused');
$(document).off('.slider');
},
barClicked: function(e) {
if(this.options.disable) return;
var x = e.pageX - this.clickableBar.offset().left;
if (this.isSingle())
this.setPosition(this.pointers.last(), x, true, true);
else {
var pointer = Math.abs(parseInt(this.pointers.first().css('left'), 10) - x + this.pointers.first().width() / 2) < Math.abs(parseInt(this.pointers.last().css('left'), 10) - x + this.pointers.first().width() / 2) ?
this.pointers.first() : this.pointers.last();
this.setPosition(pointer, x, true, true);
}
},
onChange: function(e, self, pointer, position) {
var min, max;
if (self.isSingle()) {
min = 0;
max = self.domNode.width();
} else {
min = pointer.hasClass('high') ? self.lowPointer.position().left + self.lowPointer.width() / 2 : 0;
max = pointer.hasClass('low') ? self.highPointer.position().left + self.highPointer.width() / 2 : self.domNode.width();
}
var value = Math.min(Math.max(position, min), max);
self.setPosition(pointer, value, true);
},
setPosition: function(pointer, position, isPx, animate) {
var leftPos,
lowPos = this.lowPointer.position().left,
highPos = this.highPointer.position().left,
circleWidth = this.highPointer.width() / 2;
if (!isPx) {
position = this.prcToPx(position);
}
if (pointer[0] === this.highPointer[0]) {
highPos = Math.round(position - circleWidth);
} else {
lowPos = Math.round(position - circleWidth);
}
pointer[animate ? 'animate' : 'css']({
'left': Math.round(position - circleWidth)
});
if (this.isSingle()) {
leftPos = 0;
} else {
leftPos = lowPos + circleWidth;
}
this.bar[animate ? 'animate' : 'css']({
'width': Math.round(highPos + circleWidth - leftPos),
'left': leftPos
});
this.showPointerValue(pointer, position, animate);
this.isReadonly();
},
// will be called from outside
setValue: function(value) {
var values = value.toString().split(',');
this.options.value = value;
var prc = this.valuesToPrc(values.length === 2 ? values : [0, values[0]]);
if (this.isSingle()) {
this.setPosition(this.highPointer, prc[1]);
} else {
this.setPosition(this.lowPointer, prc[0]);
this.setPosition(this.highPointer, prc[1]);
}
},
renderScale: function() {
var s = this.options.scale || [this.options.from, this.options.to];
var prc = Math.round((100 / (s.length - 1)) * 10) / 10;
var str = '';
for (var i = 0; i < s.length; i++) {
str += '<span style="left: ' + i * prc + '%">' + (s[i] != '|' ? '<ins>' + s[i] + '</ins>' : '') + '</span>';
}
this.scale.html(str);

$('ins', this.scale).each(function() {
$(this).css({
marginLeft: -$(this).outerWidth() / 2
});
});
},
getBarWidth: function() {
var values = this.options.value.split(',');
if (values.length > 1) {
return parseInt(values[1], 10) - parseInt(values[0], 10);
} else {
return parseInt(values[0], 10);
}
},
showPointerValue: function(pointer, position, animate) {
var label = $('.pointer-label', this.domNode)[pointer.hasClass('low') ? 'first' : 'last']();
var text;
var value = this.positionToValue(position);
if ($.isFunction(this.options.format)) {
var type = this.isSingle() ? undefined : (pointer.hasClass('low') ? 'low' : 'high');
text = this.options.format(value, type);
} else {
text = this.options.format.replace('%s', value);
}

var width = label.html(text).width(),
left = position - width / 2;
left = Math.min(Math.max(left, 0), this.options.width - width);
label[animate ? 'animate' : 'css']({
left: left
});
this.setInputValue(pointer, value);
},
valuesToPrc: function(values) {
var lowPrc = ((values[0] - this.options.from) * 100 / this.interval),
highPrc = ((values[1] - this.options.from) * 100 / this.interval);
return [lowPrc, highPrc];
},
prcToPx: function(prc) {
return (this.domNode.width() * prc) / 100;
},
positionToValue: function(pos) {
var value = (pos / this.domNode.width()) * this.interval;
value = value + this.options.from;
return Math.round(value / this.options.step) * this.options.step;
},
setInputValue: function(pointer, v) {
// if(!isChanged) return;
if (this.isSingle()) {
this.options.value = v.toString();
} else {
var values = this.options.value.split(',');
if (pointer.hasClass('low')) {
this.options.value = v + ',' + values[1];
} else {
this.options.value = values[0] + ',' + v;
}
}
if (this.inputNode.val() !== this.options.value) {
this.inputNode.val(this.options.value);
this.options.onstatechange.call(this, this.options.value);
}
},
getValue: function() {
return this.options.value;
},
isReadonly: function(){
this.domNode.toggleClass('slider-readonly', this.options.disable);
},
disable: function(){
this.options.disable = true;
this.isReadonly();
},
enable: function(){
this.options.disable = false;
this.isReadonly();
},
toggleDisable: function(){
this.options.disable = !this.options.disable;
this.isReadonly();
}
};

/*$.jRange = function (node, options) {
var jNode = $(node);
if(!jNode.data('jrange')){
jNode.data('jrange', new jRange(node, options));
}
return jNode.data('jrange');
};

$.fn.jRange = function (options) {
return this.each(function(){
$.jRange(this, options);
});
};*/

var pluginName = 'jRange';
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[pluginName] = function(option) {
var args = arguments,
result;

this.each(function() {
var $this = $(this),
data = $.data(this, 'plugin_' + pluginName),
options = typeof option === 'object' && option;
if (!data) {
$this.data('plugin_' + pluginName, (data = new jRange(this, options)));
$(window).resize(function() {
data.setValue(data.getValue());
}); // Update slider position when window is resized to keep it in sync with scale
}
// if first argument is a string, call silimarly named function
// this gives flexibility to call functions of the plugin e.g.
// - $('.dial').plugin('destroy');
// - $('.dial').plugin('render', $('.new-child'));
if (typeof option === 'string') {
result = data[option].apply(data, Array.prototype.slice.call(args, 1));
}
});

// To enable plugin returns values
return result || this;
};

})(jQuery, window, document);

效果


jQuery实现可拖动控制进度条_gwt