【问题标题】:When element enters viewport, scroll its entire contents horizontally before it leaves the viewport当元素进入视口时,在离开视口之前水平滚动其全部内容
【发布时间】:2019-01-29 11:20:00
【问题描述】:

我有一个包含图像的水平滚动元素,该元素位于页面下方。

首先,我有以下标记和样式。我使用了overflow:hidden,因为我不想要滚动条。为了简单起见,我还删除了一些不太重要的样式:

<ul id="players-horizontal">
    <li class="player-box"><img src="..."></li>
    <li class="player-box"><img src="..."></li>
    ...
</ul>

#players-horizontal {
    overflow: hidden;
    height: 340px;
    width: 100%;
}

#players-horizontal .player-box {
    display: inline-block;
    width: 300px;
    height: 340px;
}

#players-horizontal .player-box:first-child {
    margin-left: 90%;
}

这给了我以下观点:

当这个元素滚动到视图中时,我想水平滚动它的全部内容,直到它即将消失,这样用户就可以在向下滚动时看到它的全部内容。

元素即将离开视口时所需的外观是:

反之亦然,当用户向上滚动时应该发生反向操作。

要知道元素何时进入视口,我使用了Waypoints 插件:

var waypoints = $('#players-horizontal').waypoint(
    function(direction) {
        if (direction === 'down') {
            //console.log("Into view");
            $window.scroll(function () {
                var s = $(this).scrollTop();

            });
        } else {
            //console.log("Out of view");
            $window.scroll(function () {
                var s = $(this).scrollTop();

            });
        }
    }, { offset: '90%' }
);

但我一直不明白下一步该做什么,更具体地说,如何计算元素在离开视口之前的短时间内滚动(更改边距)多少,确保其中的所有元素在它之前显示。

如果能在终点线获得帮助,我将不胜感激。我不期望代码可以工作,虽然我会很感激,但我真的只需要一个易于理解的解释来说明所需的内容。

更新:

我刚刚尝试使用不使用 Waypoints 插件而是使用ScrollMagic 的替代方法。这无疑解除了许多所需的工作。

var scene = new ScrollMagic.Scene({triggerElement: "#players-horizontal", duration: 200})
.addTo(controller)
.on("progress", function (e) {
    console.log((e.progress * 100));
});

上面的sn-p检测元素#players-horizontal何时进入和离开视口。

当元素向下滚动时进入视口底部时,返回的值从 0 开始,在离开视口顶部之前停止在 100。当我向上滚动时,该值从 100 开始,当元素即将离开视口底部时停止在 0。所以,我肯定更接近了。

【问题讨论】:

  • 非常感谢您的更新。一段时间以来,我一直在寻找这样的解决方案。效果很好!

标签: javascript jquery html css


【解决方案1】:

我会以不同的方式思考这个问题。首先,我会考虑使用翻译使其更易于处理。你还需要一点 JS 代码来处理这个

我将拥有我将通过90% 翻译的主容器以产生您的边距效果,然后我会将其中的内容从0% 翻译成100%。翻译会考虑滚动和屏幕高度。基本上当元素进入屏幕时,我会开始翻译考虑偏移顶部和屏幕高度之间的差异。

这是第一个例子。

var h =document.querySelector('#players-horizontal');

document.body.onscroll = function(e) {
  
  var offset = h.getBoundingClientRect()
  var top = offset.top;
  if(top < window.innerHeight) {
     h.style.setProperty('--x',(top - window.innerHeight)+'%');
  }
}
body {
 margin:0;
 overflow-x:hidden;
}
.top,.bottom {
  min-height:150vh;
  background:yellow;
}
.container {
    transform:translateX(90%);
}
#players-horizontal {
    white-space:nowrap;
    margin:0;
    padding:0;
    display:inline-block; /*This is important !!*/
    transform:translateX(var(--x,0%));
    border:5px solid;
}

#players-horizontal .player-box {
    display: inline-block;
    width: 200px;
    height: 240px;
    margin:0 10px;
    background:red;
}

#players-horizontal .player-box:first-child {
    background:green;
    margin-left:0;
}
#players-horizontal .player-box:last-child {
    background:blue;
    margin-right:0;
}
<div class="top"></div>
<div class="container">
<ul id="players-horizontal">
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
</ul>
</div>
<div class="bottom"></div>

以上将创建滚动效果,但现在我们需要定义正确的值。

很明显,我们需要滚动从top = window.innerHeight (translate(0%)) 开始,当top = 0 我们希望我们的元素完全显示并且最后一项在右边缘,这意味着我们需要有@ 987654330@ 但是由于屏幕的宽度也与容器宽度相同,并且我们已经将容器平移了90%,所以我们只能到达translate(-100%) (我们可以在最后一个元素上添加负边距以纠正位置).

我们只需要将差值 (top - window.innerHeight) 转换为百分比值,将window.innerHeight 视为100%(当top=0 时)。

var h =document.querySelector('#players-horizontal');

document.body.onscroll = function(e) {
  
  var offset = h.getBoundingClientRect()
  var top = offset.top;
  if(top < window.innerHeight && top >=0) {
     h.style.setProperty('--x',(top - window.innerHeight)*(100/window.innerHeight)+'%');
  }
}
body {
 margin:0;
 overflow-x:hidden;
}
.top,.bottom {
  min-height:150vh;
  background:yellow;
}
.container {
    transform:translateX(90%);
}
#players-horizontal {
    white-space:nowrap;
    margin:0;
    padding:0;
    display:inline-block; /*This is important !!*/
    transform:translateX(var(--x,0%));
    border:5px solid;
}

#players-horizontal .player-box {
    display: inline-block;
    width: 200px;
    height: 240px;
    margin:0 10px;
    background:red;
    vertical-align:top;
}

#players-horizontal .player-box:first-child {
    background:green;
    margin-left:0;
}
#players-horizontal .player-box:last-child {
    background:blue;
    margin-right:-10vw; /*the missing 10%*/
}
<div class="top"></div>
<div class="container">
<ul id="players-horizontal">
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
</ul>
</div>
<div class="bottom"></div>

我使用了 CSS 变量(个人偏好),但这并不是强制性的,您可以简单地使用 JS 代码设置转换:

var h =document.querySelector('#players-horizontal');

document.body.onscroll = function(e) {
  
  var offset = h.getBoundingClientRect()
  var top = offset.top;
  if(top < window.innerHeight && top >=0) {
     h.style.transform="translateX("+(top - window.innerHeight)*(100/window.innerHeight)+'%)';
  }
}
body {
 margin:0;
 overflow-x:hidden;
}
.top,.bottom {
  min-height:150vh;
  background:yellow;
}
.container {
    transform:translateX(90%);
}
#players-horizontal {
    white-space:nowrap;
    margin:0;
    padding:0;
    display:inline-block; /*This is important !!*/
    transform:translateX(0%);
    border:5px solid;
}

#players-horizontal .player-box {
    display: inline-block;
    width: 200px;
    height: 240px;
    margin:0 10px;
    background:red;
    vertical-align:top;
}

#players-horizontal .player-box:first-child {
    background:green;
    margin-left:0;
}
#players-horizontal .player-box:last-child {
    background:blue;
    margin-right:-10vw;
}
<div class="top"></div>
<div class="container">
<ul id="players-horizontal">
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
    <li class="player-box"></li>
</ul>
</div>
<div class="bottom"></div>

【讨论】:

  • 感谢您抽出宝贵时间帮助我,Temani!我稍微简化了您的示例,因为我认为我最初的 90% 偏移最终毫无意义。我现在所拥有的一切都很完美。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
相关资源
最近更新 更多