记一个 bootstrap-slider 的小坑

最近在忙毕设的项目,做前端 Canvas 播放器的时候用到了 bootstrap-slider 。bootstrap-slider的确功能挺强大,但是碰到特定场景下仍然出现了问题:当 player 正在播放过程中时,拖动 slider 滑块或者点击位置跳转都操作失败,只有人品很好的少数情况下或者 player 暂停情况下能够正常改变进度。

纠其症结,问题源于在 slider 操作的事件响应之后,传递给用户回调函数的参数值,即其给的 value ,是根据 回调函数调用时 计算得出的,这就导致在回调函数调用之前如果值已经被改变的话,就会导致传递的值是一个修改后的值。

对应到我的项目中去,就是在 player 处在播放过程中,会每一帧改变进度条的数值,由于其频率较高,其往往会置于回调函数调用前,导致回调函数无法获取到正确的数值。

slidestop 事件为例,看代码:

// 我的 player.js
_play () {

  // Do things.

  // 以每 100 毫秒的时间间隔调用自身
  // 往往在事件响应后,回掉函数被调用前又被调用,修改了 slider 的值
  this.currTime += animationTimeInterval;
  this.slider.setValue(this.currTime);
  setTimeout(this._play.bind(this), animationTimeInterval * 1000);
}


// bootstrap-slider.js
this.mouseup = this._mouseup.bind(this);
document.addEventListener("mouseup", this.mouseup, false);

_mouseup: function() {
  if(!this._state.enabled) {
    return false;
  }

  // balabala

  // 当 _mouseup 事件被调用时计算当前情况下的 val。
  // 在本函数被调用前如果 val 值已经被修改,则 val 为修改后的值。
  var val = this._calculateValue(true);

  this._layout();
  this._setDataVal(val);
  // 触发用户注册的回掉函数
  this._trigger('slideStop', val);

  return false;
}

问题的源头找到了,那应该如何处理这个问题呢?

此时无论从注册的 callback 或者 bootstrap-slider 自己的 _mouseup 事件出发,都无法保证正确获取修改后的数值。因为 _play 函数可能插入到 callback 执行前,也可能插入到 _mouseup 事件前,而且其发生的概率很大。

由于监听的是 slideStop 事件,也可以说是 mouseup 事件,其一定在 mousedown 或者 mousemove 事件之后发生。当 mousedown 事件或者 mousemove 事件触发,修改了 slide 的数值之后,_play 对其进行一个判断。 _player 函数将当前值与之前的记录值进行对比,如果相差较大,则认为是 slider 受到了修改,保持当前修改后的值,只渲染当前帧,直到 _mouseup 以及 callback 被调用。

解决方案本质就是调整了 player 的操作逻辑,使程序响应点击进度条、拖动进度条的操作,而不是单单响应用户点击结束的操作。但是,为什么 mousedown 或者 mousemove 事件不会有类似的问题出现呢?见代码:

_mousemove: function(ev) {
  if(!this._state.enabled) {
    return false;
  }

  // 通过 ev 事件参数计算 percentage,并修改储存slide状态的 _state 变量
  var percentage = this._getPercentage(ev);
  this._adjustPercentageForRangeSliders(percentage);
  this._state.percentage[this._state.dragged] = percentage;
  this._layout();

  // 通过修改后的 percentage 计算得到 val 传递给 callback
  var val = this._calculateValue(true);
  this.setValue(val, true, true);

  return false;
}

关键就在于 var percentage = this._getPercentage(ev); 这一句话。 mousedown 或者 mousemove 事件的回调函数都是通过事件计算出数值的,单单 mouseup 事件是通过内部存储状态计算数值的,因此会出现刚才的问题。

我认为开发者在做开发的时候想的是 mouseup 事件肯定紧接在最后一个 mousedown 或者 mousemove 事件之后,由于前两个事件已经修改了 slide 的内部变量,因此不需要重复通过 event 进行计算,用以提升性能。这样的实现方式在大部分前端场景下是可行的,但是针对于播放器是存在 bug 的。这一问题的出现可以说是由于开发者欠考虑周全,但是也不能因此责备开发者,毕竟这样一个插件的目标场景本就不是播放器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值