在滚动事件上更新内容时Android设置scrollLeft不会更新滚动条位置

时间:2015-05-09 20:46:36

标签: javascript android google-chrome scroll touch

Setting scrollLeft does reset the scroll bar positionupdating the content works as expected但当doing both at the same time滚动条混淆且无法重置时。

要查看预期的行为与意外行为,请查看具有触摸板的设备上的每个演示,并使用触摸板在包装器内向左或向右滚动,然后尝试在Android设备上执行相同的操作。

请注意,在笔记本电脑上元素将无限滚动,在Android设备上元素将仅滚动,直到达到最初设置的“最大滚动”

会发生什么:

当用户向左或向右滚动时,将第一个子元素移动到nodeList的末尾或将最后一个子元素移动到开头,并将滚动位置重置为第一个子元素的一半。

以下是我解决问题的尝试

  1. transform: translateX(0px) see here上设置.inner,其行为比以前更差。

  2. 列出的修复程序here是针对android中的先前错误,其中设置scrollLeft根本不起作用。这根本没有帮助。

  3. 每个滚动事件的
  4. wrap.appendChild(inner),这会减慢向下滚动但没有解决问题,因为chrome会记住滚动位置。这将是一个黑客,即使我可以得到铬忘记滚动位置(看起来它可能是合理的,但将是另一个黑客)

  5. 我意识到我可以嗅探浏览器并恢复到jquery ui移动刷卡设置,但我认为如果我可以让它工作,我将不必使用外部库来模拟本机行为(和本机总是更好。)

    var log = function(event) {
      var log = document.querySelector('.log');
      log.innerHTML = event + "<br>" + log.innerHTML;
    };
    var wrap = document.querySelector('.wrap');
    var inner = document.querySelector('.inner');
    var items = document.querySelectorAll('.item');
    var controlLeft = document.createElement('a');
    controlLeft.className = 'control control-left';
    controlLeft.href = 'javascript:void(0)';
    controlLeft.innerHTML = '&lt;';
    controlLeft.onclick = function() {
      log('click left');
      inner.scrollLeft++;
    };
    wrap.appendChild(controlLeft);
    var controlRight = document.createElement('a');
    controlRight.className = 'control control-right';
    controlRight.href = 'javascript:void(0)';
    controlRight.innerHTML = '&gt;';
    controlRight.onclick = function() {
      log('click right');
      inner.scrollLeft--;
    };
    wrap.appendChild(controlRight);
    var darken1 = document.createElement('div');
    var darken2 = document.createElement('div');
    darken1.className = 'darken';
    darken2.className = 'darken';
    items[0].appendChild(darken1);
    items[2].appendChild(darken2);
    var getWidth = function(element) {
      return Number(window.getComputedStyle(element, null).getPropertyValue('width').replace('px', '')) + 1;
    };
    wrap.style.overflow = 'hidden';
    inner.style.overflowY = 'hidden';
    inner.style.overflowX = 'auto';
    wrap.style.height = inner.scrollHeight + 'px';
    window.onresize = function() {
      wrap.style.height = inner.scrollHeight + 'px';
      inner.scrollLeft = 0;
      inner.scrollLeft = getWidth(items[0]) / 2;
    };
    inner.scrollLeft = getWidth(items[0]) / 2;
    oldScroll = inner.scrollLeft;
    inner.onscroll = function() {
      if (inner.scrollLeft < oldScroll) {
        log('scroll right');
        inner.appendChild(inner.querySelector('.item:first-child'));
        inner.querySelector('.item:first-child').appendChild(darken1);
        inner.querySelector('.item:nth-child(3)').appendChild(darken2);
      } else if (inner.scrollLeft > oldScroll) {
        log('scroll left');
        var first = inner.querySelector('.item:first-child');
        var last = inner.querySelector('.item:last-child');
        inner.insertBefore(last, first);
        inner.querySelector('.item:first-child').appendChild(darken1);
        inner.querySelector('.item:nth-child(3)').appendChild(darken2);
      }
      inner.scrollLeft = 0;
      inner.scrollLeft = getWidth(items[0]) / 2;
      oldScroll = inner.scrollLeft;
    };
    *, *::before, *::after {
      box-sizing: border-box;
    }
    html,
    body {
      padding: 0;
      margin: 0;
      max-height: 100%;
      overflow: hidden;
    }
    .wrap {
      position: relative;
    }
    .control {
      font-weight: bold;
      text-decoration: none;
      display: inline-block;
      position: absolute;
      padding: 10px;
      background: rgba(255, 255, 255, 0.5);
      top: 50%;
      transform: translateY(-50%);
      color: #FFF;
      font-size: 20pt;
    }
    .control-left {
      padding-right: 20px;
      border-top-right-radius: 50%;
      border-bottom-right-radius: 50%;
      left: 0;
    }
    .control-right {
      padding-left: 20px;
      border-top-left-radius: 50%;
      border-bottom-left-radius: 50%;
      right: 0;
    }
    .inner {
      font-size: 0;
      white-space: nowrap;
      overflow: auto;
    }
    .item {
      position: relative;
      display: inline-block;
      font-size: 1rem;
      white-space: initial;
      padding-bottom: 33.3333%;
      width: 50%;
    }
    .item .darken {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(0, 0, 0, 0.8);
    }
    .item[data-n="2"] {
      background-image: url(http://www.lorempixel.com/400/300/animals);
      background-size: cover;
    }
    .item[data-n="3"] {
      background-image: url(http://www.lorempixel.com/400/300/business);
      background-size: cover;
    }
    .item[data-n="4"] {
      background-image: url(http://www.lorempixel.com/400/300/cats);
      background-size: cover;
    }
    .item[data-n="5"] {
      background-image: url(http://www.lorempixel.com/400/300/city);
      background-size: cover;
    }
    .item[data-n="6"] {
      background-image: url(http://www.lorempixel.com/400/300/food);
      background-size: cover;
    }
    .item[data-n="7"] {
      background-image: url(http://www.lorempixel.com/400/300/nightlife);
      background-size: cover;
    }
    .item[data-n="8"] {
      background-image: url(http://www.lorempixel.com/400/300/fashion);
      background-size: cover;
    }
    .item[data-n="9"] {
      background-image: url(http://www.lorempixel.com/400/300/people);
      background-size: cover;
    }
    .item[data-n="10"] {
      background-image: url(http://www.lorempixel.com/400/300/nature);
      background-size: cover;
    }
    .item[data-n="11"] {
      background-image: url(http://www.lorempixel.com/400/300/sports);
      background-size: cover;
    }
    .item[data-n="12"] {
      background-image: url(http://www.lorempixel.com/400/300/technics);
      background-size: cover;
    }
    .item[data-n="13"] {
      background-image: url(http://www.lorempixel.com/400/300/transport);
      background-size: cover;
    }
    <div class="wrap">
      <div class="inner">
        <div class="item" data-n="2"></div>
        <div class="item" data-n="3"></div>
        <div class="item" data-n="4"></div>
        <div class="item" data-n="5"></div>
        <div class="item" data-n="6"></div>
        <div class="item" data-n="7"></div>
        <div class="item" data-n="8"></div>
        <div class="item" data-n="9"></div>
        <div class="item" data-n="10"></div>
        <div class="item" data-n="11"></div>
        <div class="item" data-n="12"></div>
        <div class="item" data-n="13"></div>
      </div>
    </div>
    <div class="log">
    </div>

2 个答案:

答案 0 :(得分:1)

要暂时解决此问题,我将函数包装在超时中。超时可以短至1毫秒。我不知道为什么但是在滚动的确切事件中更改内容并设置scrollLeft会导致浏览器不重置滚动条。

Demo

inner.onscroll = function() {
  window.clearTimeout(window.updateTimeout);
  window.updateTimeout = window.setTimeout(function() {
    if (inner.scrollLeft < oldScroll) {
      log('scroll right');
      inner.appendChild(inner.querySelector('.item:first-child'));
    } else if (inner.scrollLeft > oldScroll) {
      log('scroll left')
      var first = inner.querySelector('.item:first-child');
      var last = inner.querySelector('.item:last-child');
      inner.insertBefore(last, first);
    }
    inner.querySelector('.item:first-child').appendChild(darken1);
    inner.querySelector('.item:nth-child(3)').appendChild(darken2);
    inner.scrollLeft = 0;
    inner.scrollLeft = getWidth(items[0]) / 2;
    oldScroll = inner.scrollLeft;
  }, 1);
};

虽然这确实“修复”了这个问题,但我认为这是一个黑客攻击。我打开这个问题,看看能不能得到真正的答案。

答案 1 :(得分:0)

每当您想要修改用于检查是否需要移动第一个或最后一个元素的属性时,您也会再次修改相同的信息,因此您将获得意外行为。

添加超时的技巧给人的印象是解决方案,因为它为程序提供了一些时间,因此它可以序列化信息更改。

我已对您的代码进行了一些更改,但它并未使用超时。但是,由于滚动事件的性质,根据用户在滚动行为中的配置,将滚动一个不同数量的幻灯片。

所以我建议你添加一些验证,它可以是一个计时器(hahahahaha ...),但只是为了让滚动处理程序转到一个布尔值。就像下面的snnipet一样:

inner.onscroll = function(e) {
    if (!canScroll) {
        return;
    }

    canScroll = false;

    setTimeout(function () {
        canScroll = true;
    }, 300);

    if (inner.scrollLeft < oldScrollLeft) {
    // ...

在你提问之前,inner.scrollLeft = 0然后inner.scrollLeft = getWidth(items[0]) / 2;提供的延迟感是由于原始程序强制浏览器执行的过度处理。

&#13;
&#13;
var log = function(event) {
  var log = document.querySelector('.log');
  log.innerHTML = event + "<br>" + log.innerHTML;
};
var wrap = document.querySelector('.wrap');
var inner = document.querySelector('.inner');
var items = document.querySelectorAll('.item');
var controlLeft = document.createElement('a');
controlLeft.className = 'control control-left';
controlLeft.href = 'javascript:void(0)';
controlLeft.innerHTML = '&lt;';
controlLeft.onclick = function() {
  log('click left');
  inner.scrollLeft++;
};
wrap.appendChild(controlLeft);
var controlRight = document.createElement('a');
controlRight.className = 'control control-right';
controlRight.href = 'javascript:void(0)';
controlRight.innerHTML = '&gt;';
controlRight.onclick = function() {
  log('click right');
  inner.scrollLeft--;
};
wrap.appendChild(controlRight);
var darken1 = document.createElement('div');
var darken2 = document.createElement('div');
darken1.className = 'darken';
darken2.className = 'darken';
items[0].appendChild(darken1);
items[2].appendChild(darken2);
var getWidth = function(element) {
  return Math.floor(Number(window.getComputedStyle(element, null).getPropertyValue('width').replace('px', '')));
};
wrap.style.overflow = 'hidden';
inner.style.overflowY = 'hidden';
inner.style.overflowX = 'auto';
wrap.style.height = inner.scrollHeight + 'px';
var oldScrollLeft = getWidth(items[0]) / 2;
var oldScrollWidth = inner.scrollWidth;
window.onresize = function() {
  wrap.style.height = inner.scrollHeight + 'px';
  oldScrollWidth = inner.scrollWidth;
  oldScrollLeft = getWidth(items[0]) / 2;
  inner.scrollLeft = oldScrollLeft;
};
inner.scrollLeft = getWidth(items[0]) / 2;
inner.onscroll = function(e) {
  if (inner.scrollLeft < oldScrollLeft) {
    log('scroll right');
    inner.appendChild(inner.querySelector('.item:first-child'));
    inner.querySelector('.item:first-child').appendChild(darken1);
    inner.querySelector('.item:nth-child(3)').appendChild(darken2);
  } else if (inner.scrollLeft > oldScrollLeft) {
    log('scroll left');
    var first = inner.querySelector('.item:first-child');
    var last = inner.querySelector('.item:last-child');
    inner.insertBefore(last, first);
    inner.querySelector('.item:first-child').appendChild(darken1);
    inner.querySelector('.item:nth-child(3)').appendChild(darken2);
    inner.scrollLeft = 0;
  }

  inner.scrollLeft = oldScrollLeft;
};
&#13;
*, *::before, *::after {
  box-sizing: border-box;
}
html,
body {
  padding: 0;
  margin: 0;
  max-height: 100%;
  overflow: hidden;
}
.wrap {
  position: relative;
}
.control {
  font-weight: bold;
  text-decoration: none;
  display: inline-block;
  position: absolute;
  padding: 10px;
  background: rgba(255, 255, 255, 0.5);
  top: 50%;
  transform: translateY(-50%);
  color: #FFF;
  font-size: 20pt;
}
.control-left {
  padding-right: 20px;
  border-top-right-radius: 50%;
  border-bottom-right-radius: 50%;
  left: 0;
}
.control-right {
  padding-left: 20px;
  border-top-left-radius: 50%;
  border-bottom-left-radius: 50%;
  right: 0;
}
.inner {
  font-size: 0;
  white-space: nowrap;
  overflow: auto;
}
.item {
  position: relative;
  display: inline-block;
  font-size: 1rem;
  white-space: initial;
  padding-bottom: 33.3333%;
  width: 50%;
}
.item .darken {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
}
.item[data-n="2"] {
  background-image: url(http://www.lorempixel.com/400/300/animals);
  background-size: cover;
}
.item[data-n="3"] {
  background-image: url(http://www.lorempixel.com/400/300/business);
  background-size: cover;
}
.item[data-n="4"] {
  background-image: url(http://www.lorempixel.com/400/300/cats);
  background-size: cover;
}
.item[data-n="5"] {
  background-image: url(http://www.lorempixel.com/400/300/city);
  background-size: cover;
}
.item[data-n="6"] {
  background-image: url(http://www.lorempixel.com/400/300/food);
  background-size: cover;
}
.item[data-n="7"] {
  background-image: url(http://www.lorempixel.com/400/300/nightlife);
  background-size: cover;
}
.item[data-n="8"] {
  background-image: url(http://www.lorempixel.com/400/300/fashion);
  background-size: cover;
}
.item[data-n="9"] {
  background-image: url(http://www.lorempixel.com/400/300/people);
  background-size: cover;
}
.item[data-n="10"] {
  background-image: url(http://www.lorempixel.com/400/300/nature);
  background-size: cover;
}
.item[data-n="11"] {
  background-image: url(http://www.lorempixel.com/400/300/sports);
  background-size: cover;
}
.item[data-n="12"] {
  background-image: url(http://www.lorempixel.com/400/300/technics);
  background-size: cover;
}
.item[data-n="13"] {
  background-image: url(http://www.lorempixel.com/400/300/transport);
  background-size: cover;
}
&#13;
<div class="wrap">
  <div class="inner">
    <div class="item" data-n="2"></div>
    <div class="item" data-n="3"></div>
    <div class="item" data-n="4"></div>
    <div class="item" data-n="5"></div>
    <div class="item" data-n="6"></div>
    <div class="item" data-n="7"></div>
    <div class="item" data-n="8"></div>
    <div class="item" data-n="9"></div>
    <div class="item" data-n="10"></div>
    <div class="item" data-n="11"></div>
    <div class="item" data-n="12"></div>
    <div class="item" data-n="13"></div>
  </div>
</div>
<div class="log">
</div>
&#13;
&#13;
&#13;