可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to implement a page where there are 4 jQuery-UI sliders, and I want to make it so the combined total of all 4 sliders will never go over 400.
I don't mind which way this is implemented, it can be from a 0 start, and as soon as you change 1 slider, the remaining available total decreases or setting a slider past the maximum, decreases the values on the other sliders.
P.S. The sliders go in increments of 10.
All ideas & suggestions are welcome, and I've set up a jsFiddle if you'd like to test.
回答1:
Well here ya go:
var sliders = $("#sliders .slider");
sliders.each(function() {
var value = parseInt($(this).text(), 10),
availableTotal = 400;
$(this).empty().slider({
value: 0,
min: 0,
max: 400,
range: "max",
step: 10,
slide: function(event, ui) {
// Update display to current value
$(this).siblings().text(ui.value);
// Get current total
var total = 0;
sliders.not(this).each(function() {
total += $(this).slider("option", "value");
});
// Need to do this because apparently jQ UI
// does not update value until this event completes
total += ui.value;
var max = availableTotal - total;
// Update each slider
sliders.not(this).each(function() {
var t = $(this),
value = t.slider("option", "value");
t.slider("option", "max", max + value)
.siblings().text(value + '/' + (max + value));
t.slider('value', value);
});
}
});
});
Here's a simple demo of this: http://jsfiddle.net/yijiang/Y5ZLL/4/
回答2:
Made an updated version of the above answer to show percentages of 100%. So as you adjust one slider up, the other two decrease making the percentage of each slider add up to 100%. Also made it easy to set initial values
JSfiddle
var sliders = $("#sliders .slider");
var availableTotal = 100;
sliders.each(function() {
var init_value = parseInt($(this).text());
$(this).siblings('.value').text(init_value);
$(this).empty().slider({
value: init_value,
min: 0,
max: availableTotal,
range: "max",
step: 2,
animate: 0,
slide: function(event, ui) {
// Update display to current value
$(this).siblings('.value').text(ui.value);
// Get current total
var total = 0;
sliders.not(this).each(function() {
total += $(this).slider("option", "value");
});
// Need to do this because apparently jQ UI
// does not update value until this event completes
total += ui.value;
var delta = availableTotal - total;
// Update each slider
sliders.not(this).each(function() {
var t = $(this),
value = t.slider("option", "value");
var new_value = value + (delta/2);
if (new_value < 0 || ui.value == 100)
new_value = 0;
if (new_value > 100)
new_value = 100;
t.siblings('.value').text(new_value);
t.slider('value', new_value);
});
}
});
});
回答3:
I found when the other sliders (the ones other than the one you're moving) move around, it's distracting. I've also modified the Yi Jiang fiddle to now simply have it stop when you reach a total of 400. If you want that slider to go higher, you'll first have to lower one of the other ones much like how the first one, but it keeps the slider relative to the overall total.
This means that when you have one slider at 25% and another at 50%, they look like they are at 25 and 50 respectively.
JSfiddle
var sliders = $("#sliders .slider");
sliders.each(function() {
var value = parseInt($(this).text(), 10),
availableTotal = 400;
$(this).empty().slider({
value: 0,
min: 0,
max: 400,
range: "max",
step: 10,
animate: 100,
slide: function(event, ui) {
// Get current total
var total = 0;
sliders.not(this).each(function() {
total += $(this).slider("option", "value");
});
var max = availableTotal - total;
if (max - ui.value >= 0) {
// Need to do this because apparently jQ UI
// does not update value until this event completes
total += ui.value;
console.log(max-ui.value);
$(this).siblings().text(ui.value);
} else {
return false;
}
}
});
});
回答4:
Not a single one of these answers was the least bit effective for changing sliders in relationship to each other in any effective way...most of them left one or more out of the calculations or did not respect the overall limit , I needed something for allowing a user to pick their chips in an HTML5 game so I came up with this if anyone else ever has a similar issue... if you don't need to tie it to something like changing betting chips then just take out the stop option or change it to suit your needs
<div id="chip_holder" style="float:right;margin-right:20px;">
<ul id="sliders">
<?php
$chips = array("1" => array("blue", "1 Point", "1"), "5" => array("red", "5 Points", "5"), "10" => array("gold", "10 Points", "10"));
$t = 0;
$value_per_row = floor($my_points / count($chips));
$totalc = 0;
foreach($chips as $key => $value){
$value = floor($value_per_row / $value[2]);
$totalc = $totalc + $value_per_row;
?>
<li style="display:inline-block;">
<input type="number" style="display:none;" id="hidden_value_<?php echo $key; ?>" value="<?php echo floor($value); ?>" min="0" max="<?php echo $my_points; ?>" step="<?php echo $chips[$key][2]; ?>" />
<span id="slide_<?php echo $key; ?>" title="<?php echo $key; ?>" class="chip_slider" alt="<?php echo $key / $my_points; ?>"></span>
<span id="chip_label_<?php echo $key; ?>" title="<?php echo $key; ?>" class="chip_label"><?php echo $value; ?></span>
</li>
<?php
$t++;
}
if($totalc < $my_points){
$min = min(array_keys($chips));
$remainder = floor(($my_points - $totalc) / $chips[$min][2]);
?>
<script>
$('#hidden_value_<?php echo $min; ?>').val(parseInt($('#hidden_value_<?php echo $min; ?>').val()) + parseInt(<?php echo $remainder; ?>));
$('#chip_label_<?php echo $min; ?>').text(parseInt($('#hidden_value_<?php echo $min; ?>').val()));
</script>
<?php } ?>
<li id="checkout_button" onclick="javascript: checkout_now();"><?php echo CASHOUT; ?></li>
</ul>
<ul id="chips_stay_put">
<?php
$t = 0;
foreach($chips as $key => $value){
?>
<li class="chip_holder" style="width:70px;">
<span id="chip_holder_<?php echo $key; ?>" class="<?php echo $value[0]; ?>" alt="<?php echo $key; ?>"></span>
</li>
<?php
$t++;
}
?>
</ul>
</div>
<script>
function drop_chips(id, chips){
$('.chip_label').each(function(){
id =$(this).attr('id');
idx =$('#' + id).attr('title');
chips = parseInt($('#chip_label_' + idx).text());
cls = $('#chip_holder_' + idx).attr('class');
$('#chip_holder_' + idx).html('');
m = minMaxTitle($('.chip.' + cls));
if(m>0){
start = 0;
}else{
start = m;
}
htmlH = '';
while(m<=chips){
start= start + m;
zIndex = parseInt(start) + parseInt(100);
htmlH += '<span id="chip_' + idx + '_' + m + '" class="chip ' + cls + '" style="position:absolute;top:-'+ (m * 3) + 'px;z-index:' + zIndex + ';" alt="' + cls + '" title="' +m+ '">' + idx + '</span>';
m++;
}
$('#chip_holder_' + idx).html(htmlH);
$('.chip').draggable({
drag: function( event, ui ) {
var snapTolerance = $(this).draggable('option', 'snapTolerance');
var topRemainder = ui.position.top % 20;
var leftRemainder = ui.position.left % 20;
if (topRemainder <= snapTolerance) {
ui.position.top = ui.position.top - topRemainder;
}
if (leftRemainder <= snapTolerance) {
ui.position.left = ui.position.left - leftRemainder;
}
} ,
revert : function(event, ui) {
// on older version of jQuery use "draggable"
// $(this).data("draggable")
// on 2.x versions of jQuery use "ui-draggable"
// $(this).data("ui-draggable")
$(this).data("uiDraggable").originalPosition = {
top : 0,
left : 0
};
// return boolean
return !event;
// that evaluate like this:
// return event !== false ? false : true;
}
});
});
}
var sliders = $("#sliders .chip_slider");
sliders.each(function() {
var slider_id;
var value = parseInt($(this).text(), 10),
availableTotal = parseInt($('#my_points_hidden').val());
$(this).empty().slider({
value: parseInt($('#' + $(this).attr('id')).prev('input').val()),
min: 0,
max: parseInt($('#' + $(this).attr('id')).prev('input').attr('max')),
range:parseInt($('#' + $(this).attr('id')).prev('input').attr('max')),
orientation:"vertical",
step: 1,
animate: 100,
stop: function( event, ui ) { drop_chips() },
slide: function(event, ui) {
// Update display to current value
$(this).siblings('.value').text(ui.value);
// Get current total
var total = 0;
var slider_id = $(this).attr('title');
sliders.not(this).each(function() {
total += $(this).slider("option", "value");
});
// Need to do this because apparently jQ UI
// does not update value until this event completes
total += ui.value;
var delta = availableTotal - total;
// Update each slider
sliders.not(this).each(function() {
var t = $(this),
value = t.slider("option", "value");
var new_value = value + (delta/2);
if (new_value < 0 || ui.value == 100)
new_value = 0;
if (new_value > 100)
new_value = 100;
t.siblings('.value').text(new_value);
t.slider('value', new_value);
id = $(this).attr('id');
title = $('#' + id).attr('title');
initial_slider = total - new_value;
console.log(slider_id);
$('#chip_label_' + slider_id).text(parseInt(parseInt(ui.value) / parseInt($('#hidden_value_' + slider_id).attr('step'))));
$('#chip_label_' + title).text(parseInt(parseInt(new_value) / parseInt($('#hidden_value_' + title).attr('step'))));
});
}
});
});
</script>
回答5:
This thread was a great launching point for me to work towards building this, hope it helps others. https://codepen.io/jmester13/pen/jOEyNEe
$(document).ready(function() {
slider = new Slider();
});
var Slider = (function() {
var Slider = function() {
this.initialise();
}
Slider.prototype = {
initialise: function() {
this.vars();
this.setup();
this.slideEvent();
},
vars: function() {
// vars
_this = this;
this.container = $('.sliders');
this.slider = $('.slider');
this.slide = $('.slide');
this.controls = $('.control');
this.value = $('.value');
this.totalPercentage = 100;
},
setup: function() {
// set equal width depending on how many sliders there are when initalised
var counter = 0;
this.slide.each(function() {
counter++;
});
var initWidth = this.totalPercentage / counter;
this.slide.width(initWidth + '%');
this.slide.attr('data-percent', initWidth + '%');
this.value.text(initWidth + '%');
},
getPercentWidth: function(target) {
// get percentage of current width
target.attr('data-percent', (100 * parseFloat(target.css('width')) / parseFloat(target.parent().css('width'))));
},
slideEvent: function() {
// listen for mouse down on the controls
this.controls.on('mousedown', function(event) {
this.slideDrag(event);
}.bind(this));
},
slideDrag: function(event) {
event.preventDefault();
this.target = $(event.target);
this.prevMousePos = 0;
this.target.parent().addClass('active');
// listen mousemove and mouseup events on the document: only if the mousedown happend on one of the controls
$(document).on('mousemove', this.slideMove);
$(document).on('mouseup', this.slideEnd);
},
slideMove: function() {
_this.mousePos = event.pageX;
_this.amount = [];
// get info on widths, offsets and positions
var offset = _this.slider.offset().left;
var sliderWidth = _this.slider.width();
var posX = Math.min(Math.max(0, _this.mousePos - offset), sliderWidth);
// checks direction
if (_this.mousePos < _this.prevMousePos) {
_this.direction = 'left';
} else {
_this.direction = 'right';
}
//console.log(_this.direction);
// update mouse position
_this.prevMousePos = _this.mousePos;
// set new width of the active slider
_this.target.parent().width(posX / sliderWidth * 100 + '%');
_this.calcPercent();
},
calcPercent: function() {
var totalWidth = 0;
var sliderLength = 0;
var leftoverAmount = 0;
// loop through each slide
_this.slide.each(function() {
sliderLength++;
_this.getPercentWidth($(this));
if ($(this).hasClass('active')) {
// set active percentage
_this.active = parseFloat($(this).attr('data-percent')).toFixed(0);
} else {
// add non active widths into an array
_this.amount.push(parseFloat($(this).attr('data-percent')).toFixed(0));
}
//totalWidth += parseFloat($(this).attr('data-percent'));
});
// find out the leftover amount
leftoverAmount = _this.totalPercentage - _this.active;
_this.nonActiveAmount = 0;
$.each(_this.amount, function() {
_this.nonActiveAmount += parseFloat(this) ;
});
var x = leftoverAmount / 100;
var y = _this.nonActiveAmount / 100;
var z = _this.active;
_this.slide.each(function() {
if (!$(this).hasClass('active') || !$(this).hasClass('locked')) {
console.log($(this));
var v = x * (parseFloat($(this).attr('data-percent')) / y);
$(this).width(v + '%');
$(this).find('.value').text(Math.round(v) + '%');
}
});
},
slideEnd: function() {
// kill the events on mouse up.
_this.target.parent().removeClass('active');
$(this).off('mousemove', slider.slideMove);
$(this).off('mouseup', slider.slideEnd);
},
}
return Slider;
}());
回答6:
It was a good experience for me.I hope it will also helpful for others.
$(document).ready(function(){
var sliders = $(".slider");
var available = 100;
sliders.slider({
value: 0,
min: 0,
max: available,
range: "max",
step: 1,
animate: 0,
slide: function(event, ui){
var total = 0;
var arr = new Array();
sliders.not(this).each(function() {
var t = $(this);
arr.push(t);
total += t.slider("option", "value");
});
total += ui.value;
var delta = available - total;
if(delta<0){
return false;
}
$(this).parent('.slidecontainer').find('.setval').text(ui.value);
$.each(arr, function(idx, ele){
let v = ele.slider("option", "value");
let vm = v + delta;
$(ele).parent('.slidecontainer').find('.max').text(vm);
});
}
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="col-lg-8">
<div class="slidecontainer">
<div class="slider"></div>
<p class="value">Value:<span class="setval"></span>
Max: <span class="max"></span>
</p>
</div>
</div>
<div class="col-lg-8">
<div class="slidecontainer">
<div class="slider"></div>
<p class="value">Value:<span class="setval"></span>
Max: <span class="max"></span>
</p>
</div>
</div>