jQuery滑块拖动控制数字的增加和减少

简介: jQuery滑块拖动控制数字的增加和减少
<!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 type="text/javascript" src="js/jquery-1.7.2.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);

效果如下:

相关文章
|
JavaScript 前端开发
jQuery实现可拖动控制进度条
jQuery实现可拖动控制进度条
47 0
|
JavaScript 前端开发 开发者
|
JavaScript
多图切换jQuery图片滑块插件
在线演示 本地下载
906 0
|
JavaScript
jQuery可放大预览的图片滑块
在线演示 本地下载
743 0