【JavaScript吉光片羽】--- 滑动条


灯光的亮度控制需要一个滑动条,先借用lamp源码中Bar:

var Bar = function (opt) {
    var defaults = {
        $id: "", // 进度条dom节点id
        min: 1, // 刻度最小值
        stepCount: 5, // 刻度步数
        step: 1, // 刻度步长
        $alpha: "",//显示亮度的id
        touchEnd: function () { } // 拖动完成回调
    };
    this.option = $.extend(defaults, opt);
    this.barNode = $("#" + this.option.$id);
    this.parentNode = this.barNode.parents(".J_slider_box");
    this.sliderNode = this.barNode.find(".J_slider");
    this.fillNode = this.barNode.find(".J_fill");
    this.valNode = this.barNode.find(".J_value");
    this.val = this.option.min;
    // this.valNode.text(this.val);

    this._init();
    return this;
}
Bar.prototype = {
    /**
     * 根据比例值来重新渲染进度条的位置
     * @param ratio 取值:0~1
     */
    refreshPos: function (ratio) {
        if (ratio >= 1 || ratio < 0) { // 等于1时,js的%取值有问题,故排除
            return;
        }
        // 根据触点位置更新进度条
        var percentage = ratio * 100;
        this.sliderNode.css("left", percentage + "%");
        this.fillNode.css("width", percentage + "%");

        var unit = 1 / this.option.stepCount,
            halfUnit = unit / 2,
            a = Math.floor(ratio / unit),
            b = ratio % unit,
            index = a + (b < halfUnit ? 0 : 1);
        this.val = this.option.min + index * this.option.step;
        if (this.option.$alpha) {
            $("#" + this.option.$alpha).html(this.val);
        } else {
            this.valNode.text(this.val);
        }
    },
    /**
     * 设置指定的进度值
     */
    setVal: function (val) {
        var ratio = (val - this.option.min) / (this.option.step * this.option.stepCount);
        this.refreshPos(ratio);
    },
    _init: function () {
        var bar = this;
        if (!(bar.barNode.width() > 0)) {
            setTimeout(function () {
                bar._init();
            }, 100); // 直到vm渲染完成之后才能取得正确的dom高宽
            return;
        }
        bar.leftDis = bar.barNode.offset().left;
        bar.sliderWidth = bar.barNode.width();

        bar.barNode.on("touchmove", function (e) {
            e.preventDefault();
            // bar.parentNode.addClass("on");
            var touch = e.changedTouches ? e.changedTouches[0] : e;
            var ratio = (touch.pageX - bar.leftDis) / bar.sliderWidth;
            bar.refreshPos(ratio);
        });

        bar.barNode.on("touchend", function (e) {
            e.preventDefault();
            //bar.parentNode.removeClass("on");
            var touch = e.changedTouches ? e.changedTouches[0] : e;
            var ratio = (touch.pageX - bar.leftDis) / bar.sliderWidth;
            bar.refreshPos(ratio);
            bar.option.touchEnd(bar.val);
        });

        bar.refreshPos(this.val);

    }
};
View Code

html:

     <div class="lightsider">
                <div id="lightsider" class="slider_box J_slider_box">
                    <i class="slider_box_icon icon dark"></i>
                    <div id="lightBar" class="slider_box_bar">
                        <div class="slider_box_slider J_slider" style="left:0%">
                            <p class="slider_box_slider_label J_value"></p>
                            <i class="slider_box_slider_touch"></i>
                        </div>
                        <div class="slider_box_line">
                            <span class="slider_box_line_fill J_fill" style="width:0%"></span>
                        </div>
                    </div>
                    <i class="slider_box_icon icon light"></i>
                </div>
            </div>  

css:

.slider_box {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -webkit-align-items: center;
      -ms-flex-align: center;
          align-items: center;
}

.slider_box_icon {
  display: block;
  width: 35px;
  height: 35px;
}
.slider_box_bar {
  position: relative;
  margin: 0 10px;
  padding: 33px 0;
  -webkit-box-flex: 1;
  -webkit-flex: 1;
      -ms-flex: 1;
          flex: 1;
}
.slider_box_slider {
  position: absolute;
  height: 33px;
  top: 0;
  left: 0;
  z-index: 1;
  -webkit-transform: translate(-50%, 0);
      -ms-transform: translate(-50%, 0);
          transform: translate(-50%, 0);
}

.slider_box_slider_touch {
  position: absolute;
  left: 50%;
  bottom: -11px;
  margin-left: -8px;
  width: 20px;
  height: 20px;
  border-radius: 15px;
  background-color: white;
    border: 1px solid rgb(195, 194, 194);
}
.slider_box_line {
  position: relative;
  height: 4px;
  border-radius: 4px;
  background-color: rgb(195, 194, 194);
}
.slider_box_line_fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 4px;
  background-color: gold;
  border-radius: 4px;
}

JavaScript 调用:

   var bar = new Bar({ $id: "lightsider", stepCount: 100, min: 0, $alpha: "alpha" });

stepCount相当于最大长度。$alpha用来显示亮度值。效果如下

主要的原理就是监听 touchmove事件,通过移动的pageX减去圆点左边的位置除以滑动条的总长度得到比率,最后换算成step

   bar.leftDis = bar.barNode.offset().left;
        bar.sliderWidth = bar.barNode.width();

        bar.barNode.on("touchmove", function (e) {
            e.preventDefault();
            // bar.parentNode.addClass("on");
            var touch = e.changedTouches ? e.changedTouches[0] : e;
            var ratio = (touch.pageX - bar.leftDis) / bar.sliderWidth;
            bar.refreshPos(ratio);
        });

如果是竖着的滑动条呢? 暂且定义一个UpBar对象:

var UpBar = function (opt) {
    var defaults = {
        $id: "", // 进度条dom节点id
        min: 1, // 刻度最小值
        stepCount: 5, // 刻度步数
        step: 1, // 刻度步长
        $alpha: "",//显示亮度的id
        touchEnd: function () { } // 拖动完成回调
    };
    this.option = $.extend(defaults, opt);
    this.barNode = $("#" + this.option.$id);
    this.parentNode = this.barNode.parents(".J_slider_box");
    this.sliderNode = this.barNode.find(".J_slider");
    this.fillNode = this.barNode.find(".J_fill");
    this.valNode = this.barNode.find(".J_value");
    this.val = this.option.min;
    // this.valNode.text(this.val);

    this._init();
    return this;
}
UpBar.prototype = {
    /**
     * 根据比例值来重新渲染进度条的位置
     * @param ratio 取值:0~1
     */
    refreshPos: function (ratio) {
        if (ratio >= 1 || ratio < 0) { // 等于1时,js的%取值有问题,故排除
            return;
        }
        // 根据触点位置更新进度条
        var percentage = ratio * 100;
        this.sliderNode.css("bottom", percentage + "%");
        this.fillNode.css("height", percentage + "%");

        var unit = 1 / this.option.stepCount,
            halfUnit = unit / 2,
            a = Math.floor(ratio / unit),
            b = ratio % unit,
            index = a + (b < halfUnit ? 0 : 1);
        this.val = this.option.min + index * this.option.step;
        if (this.option.$alpha) {
            $("#" + this.option.$alpha).html(this.val);
        } else {
          //  this.valNode.text(this.val);
        }
    },
    /**
     * 设置指定的进度值
     */
    setVal: function (val) {
        var ratio = (val - this.option.min) / (this.option.step * this.option.stepCount);
        this.refreshPos(ratio);
    },
    _init: function () {
        var bar = this;
        if (!(bar.barNode.height() > 0)) {
            setTimeout(function () {
                bar._init();
            }, 100); // 直到vm渲染完成之后才能取得正确的dom高宽
            return;
        }
        bar.topDis = bar.barNode.offset().top;
        bar.sliderHeight = bar.barNode.height();

        bar.barNode.on("touchmove", function (e) {
            e.preventDefault();
            var touch = e.changedTouches ? e.changedTouches[0] : e;
            var ratio =1- (touch.pageY - bar.topDis) / bar.sliderHeight;
            bar.refreshPos(ratio);
        });

        bar.barNode.on("touchend", function (e) {
            e.preventDefault();
            var touch = e.changedTouches ? e.changedTouches[0] : e;
            var ratio =1- (touch.pageY - bar.topDis) / bar.sliderHeight;
            bar.refreshPos(ratio);
            bar.option.touchEnd(bar.val);
        });

        bar.refreshPos(this.val);

    }
};
View Code

css:

.slider_box_slider_up {
  position: absolute;
  width: 33px;
  top: 0;
  right: -20px;
  z-index: 1;
  -webkit-transform: translate(-50%, 0);
      -ms-transform: translate(-50%, 0);
          transform: translate(-50%, 0);
}
.slider_box_slider_touch_up {
  position: absolute;
  width: 20px;
  height: 20px;
    bottom: -10px;
    left: 0;
  border-radius: 15px;
  background-color: white;
    border: 1px solid rgb(195, 194, 194);
}
.slider_box_line_up {
  width: 4px;
    height: 100%;
  border-radius: 4px;
  position: relative;
    margin: 0 auto;
  background-color: rgb(195, 194, 194);
}
.slider_box_line_fill_up {
  position: absolute;
  bottom:0;
  left: 0;
  width: 4px;
  background-color: gold;
  border-radius: 4px;
}

html:

 <div class="soundBar">
                <div id="soundBar" class="slider_box_up J_slider_box">
                    <div class="slider_box_line_up">
                        <span class="slider_box_line_fill_up J_fill" style="height: 0%"></span>
                    </div>
                    <div class="slider_box_slider_up J_slider" style="bottom: 0%">
                        <i class="slider_box_slider_label J_value"></i>
                        <i class="slider_box_slider_touch_up"></i>
                    </div>
                </div>
            </div>

调用:

  var bar = new UpBar({ $id: "soundBar", stepCount: 100, min: 0 });

效果如下:

主要的区别是left-->bottom,width-->height,另外一个因为y轴是以左上角为0,0的,touch.pageY越往下越大,所以算比率的时候用要这样:

 bar.topDis = bar.barNode.offset().top;
        bar.sliderHeight = bar.barNode.height();
        bar.barNode.on("touchmove", function (e) {
            e.preventDefault();
            var touch = e.changedTouches ? e.changedTouches[0] : e;
            var ratio =1- (touch.pageY - bar.topDis) / bar.sliderHeight;
            bar.refreshPos(ratio);
        });

有兴趣也可以合二为一。