检查元素是否在视口中,基于水平滚动

3

我正在制作一个横向滚动/水平布局的网站。我使用一个函数在“正常”的垂直布局网站上测试元素是否在视口中,以便在其进入视图时添加类、动画等效果。

我试图在水平布局中实现同样的效果,但一直未能成功。

以下是该函数的常规版本 -

 $.fn.isInViewport = function() {
    if ( $(this).length ) {
        var elementTop = $(this).offset().top;
    }
    var elementBottom = elementTop + $(this).outerHeight();
    var viewportTop = $(window).scrollTop();
    var viewportBottom = viewportTop + $(window).height();
    return elementBottom > viewportTop && elementTop < viewportBottom;
};

以下是我尝试水平布局的方法,但没有成功。

 $.fn.isInViewport = function() {
    if ( $(this).length ) {
        var elementLeft = $(this).offset().left;
    }
    var elementRight = elementLeft + $(this).outerWidth();
    var viewportLeft = $(window).scrollLeft();
    var viewportRight = viewportLeft + $(window).width();
    return elementRight > viewportLeft && elementLeft < viewportRight;
};

你可以这样调用该函数。
 $(".element").each(function() {
    if ( $(this).isInViewport() ) {
        $(this).addClass("animate-element");
    }
});

6
如果您不需要兼容IE,请查看Intersection Observer API - D M
1
水平检查的实现运行良好 https://jsfiddle.net/taLzu8er/1/。唯一的问题似乎是变量 elementLeft 在 if 语句的作用域内定义。声明应该在 if 语句之前。 - the Hutt
@onkarruikar,如果使用的是let,那么这将是正确的。但由于是var,并且这里只有一个函数,因此无论在if内部还是外部声明,作用域都是相同的。(我同意最好还是在外部声明,因为这样实际作用域与视觉感知更匹配。) - Robin Zigmond
2个回答

4

使用jquery很容易,你只需要 $(element).on('scroll',(--function--)) 就可以了,然后你就可以使用 $(this).offset().left 来获取它左侧的像素值,当你得到左侧偏移量之后,你就可以随意操作了。查看下面的代码片段以获取可工作的示例。(如果可能,请在像手机一样的较小屏幕上运行)

$("#timeline").on('scroll', function() {

    $("#timeline .each").each(function(){
        let left = $(this).offset().left;

        if(left >-50 && left< (window.innerWidth - 100)){
            $(this).addClass('mvisible')
        }
        else{
            if($(this).hasClass('mvisible')){
                $(this).removeClass('mvisible')
            }
        }
    });

});
.timeline{overflow-x:auto;width:100%}

.timeline .warp{display:flex;width:1600px;padding:50px 100px 50px 30px;}
.timeline .each{width:185px;}
.timeline .desc{padding:15px;border-radius:4px;background:#08f;color:#fff;width:100%;transform:translateY(50px);opacity:0;transition:0.4s}
.timeline .mvisible .desc{transform:translateY(0);opacity:1}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="timeline" id="timeline">
    <div class="warp">
        <div class="each mvisible">
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
        <div class="each">
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
        <div class="each">
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
        <div class="each" >
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
        <div class="each" >
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
        <div class="each">
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
        <div class="each">
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
        <div class="each">
            <div class="desc">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
            </div>
        </div>
    </div>
</div>


2

如评论中所提到的IntersectionObserver是一个很好的起点

const inViewObserver = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // do stuff when in view
      entry.target.classList.add('in-view')
      document.body.dataset.log = 'Element in view - well done '
    } else {
      // do stuff when not in view
      entry.target.classList.remove('in-view')
      document.body.dataset.log = 'Element not in view - try to find it '
    }
  })
}, { threshold: .5 })

const elm = document.querySelector('.element')
inViewObserver.observe(elm)
body {
  /* trigger scroll in both directions */
  width: 300vw;
  height: 300vh;
  display: grid;
  place-items: center;
}

body::before {
  content: attr(data-log);
  position: fixed;
  top: 0;
  left: 0;
}

.element {
  background: tomato;
  width: 10rem;
  height: 10rem;
  transition: all 600ms 300ms;
  transform: scale(0.25) rotate(360deg);
}

.in-view {
  background: olive;
  transform: none;
  border-radius: 1rem; 
}
<div class="element"></div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接