【问题标题】:Check if element is in viewport based on horizontal scroll根据水平滚动检查元素是否在视口中
【发布时间】:2022-01-24 23:10:03
【问题描述】:

我正在构建一个横向滚动/水平布局网站。我使用一个函数来测试一个元素是否在“正常”垂直布局站点的视口中,以便在它进入视图后添加类、动画等。

我正在尝试为水平布局获得相同的效果,但无济于事。

这是函数的常规版本-

 $.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");
    }
});

【问题讨论】:

  • 查看Intersection Observer API,只要您不需要 IE 兼容性。
  • 水平检查的实现工作正常jsfiddle.net/taLzu8er/1。唯一的问题是变量 elementLeft 是在 if 语句的范围内定义的。声明应该在 if 语句之前。
  • @onkarruikar 如果使用了let,那将是正确的,但由于它是var,并且这里只有一个函数,因此无论在if 内部还是外部声明,范围都是相同的。 (我同意它仍然更好地声明在外面,因为这样实际的范围更符合人们的视觉感知。)

标签: javascript html jquery css


【解决方案1】:

使用 jquery 非常简单,你所要做的就是 $(element).on('scroll',(--function--)) 然后你可以使用 $(this).offset().left 来得到左边的像素,当你得到左边的偏移量时,你可以做任何你想做的事情。检查下面的 sn-p 以获取工作示例。 (如果可能在像手机这样的小屏幕上运行)

$("#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】:

    正如 cmets 中提到的,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; 
    }
    &lt;div class="element"&gt;&lt;/div&gt;

    【讨论】:

      猜你喜欢
      • 2020-02-13
      • 2015-09-05
      • 1970-01-01
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多