【问题标题】:Add class to element when scrolled into view (scrollable div)滚动到视图时向元素添加类(可滚动的 div)
【发布时间】:2014-10-01 11:20:40
【问题描述】:

是否有一种解决方案可以在滚动时向视图中的元素添加类,而在视图外时移除?这需要适用于可滚动的 div。到目前为止,我已经找到了一些解决方案,但它们似乎只适用于 body...而不是可滚动的 div。

如果您知道有一个插件,我很乐意使用它。像这样的...

if ($('.journal-slider .each-slide img').inViewport() ) {
    $(this).addClass('in-view');
} else {
   $('.journal-slider .each-slide img').removeClass('in-view');
}

谢谢, 回复

【问题讨论】:

标签: javascript jquery html css


【解决方案1】:

您可以制作自己的 jQuery 插件来执行此操作。这样的东西需要两个函数(whenInView,whenNotInView):

$('.journal-slider .each-slide img').inViewport(
    function(){$(this).addClass("am-in-view");},
    function(){$(this).removeClass("am-in-view");}
);

它在滚动(或调整大小)时测试目标元素当前是否在视口内并调用相关函数。

这是演示片段的全部内容。在此示例中,我向.am-in-view 类添加了一个动画,以便您可以看到它在元素进入视口时工作。到目前为止,这还没有在 Chrome 以外的任何东西上进行过测试。随意使用和改进。

/*! inViewport 0.0.1 
 *  jQuery plugin by Moob
 * ======================== 
 *  (requires jQuery) 
 */  
(function ($) {

    var vph=0;
    function getViewportDimensions(){
        vph = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
    }
    getViewportDimensions();    
    //on resize/scroll
    $(window).on('resize orientationChanged', function(){
        getViewportDimensions();
    });            
    
    $.fn.inViewport = function (whenInView, whenNotInView) {                  
        return this.each(function () {
            var el = $(this),
                inviewalreadycalled = false,
                notinviewalreadycalled = false;                            
            //on resize/scroll
            $(window).on('resize orientationChanged scroll', function(){
                checkInView();
            });               
            function checkInView(){
                var rect = el[0].getBoundingClientRect(),
                    t = rect.top,
                    b = rect.bottom;
                if(t<vph && b>0){
                    if(!inviewalreadycalled){
                        whenInView.call(el);
                        inviewalreadycalled = true;
                        notinviewalreadycalled = false;
                    }
                } else {
                    if(!notinviewalreadycalled){
                        whenNotInView.call(el);
                        notinviewalreadycalled = true;
                        inviewalreadycalled = false;
                    }
                }
            }
            //initial check
            checkInView();                
        });
    }             
}(jQuery));
html, body {
    margin:0;
}
.me, .not-me {
    padding:20px;
    border:1px solid #aaa;
    margin:20px;
}
.am-in-view {
    background-color:pink;
    -webkit-transition: all 1500ms;
    -moz-transition: all 1500ms;
    -o-transition: all 1500ms;
    transition: all 1500ms;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet, pariatur.</p>
    <p>Saepe, eligendi nihil totam dolorum reprehenderit! Repellat omnis neque quasi.</p>
    <p>Eos cumque voluptatum placeat eius nisi facere neque nesciunt praesentium.</p>
    <p>Eos qui consectetur voluptatem eum, labore accusamus tempora distinctio sunt?</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi, sit.</p>
    <p>A veritatis quis quae totam accusamus repellendus adipisci corporis soluta.</p>
    <p>Debitis animi dolor distinctio ratione dolorum ex aperiam maiores fugit?</p>
    <p>Incidunt non consequatur porro provident recusandae sunt architecto repellat enim.</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, reprehenderit?</p>
    <p>Neque tempora perferendis dolor, mollitia debitis sunt voluptas ea ut!</p>
    <p>Maiores earum officia corporis, sint voluptatem, in laboriosam perferendis asperiores?</p>
    <p>Odit dolor voluptate laboriosam voluptatem accusamus aperiam explicabo at provident.</p>
</div>
<div class="not-me">
    <p>I'm totally normal</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam, accusamus.</p>
    <p>Quisquam architecto repellat facere amet sapiente dolore obcaecati harum fuga.</p>
    <p>Tempora labore, unde necessitatibus ipsam repellat architecto, aliquam autem at.</p>
    <p>Sapiente quis doloremque a illum, repellat, eius corporis ab placeat.</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptate, assumenda!</p>
    <p>Nesciunt corrupti, eaque dolores ut libero ipsam dolorem laudantium saepe.</p>
    <p>Similique quisquam quod esse expedita, voluptate quia nobis? Cum, tempore.</p>
    <p>Amet voluptatem eaque non, praesentium tenetur molestias minima architecto laboriosam?</p>
</div>
<div class="me">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore, ex?</p>
    <p>Perferendis hic, sint maxime similique quia autem cum quasi? Sed.</p>
    <p>Nemo ratione aliquid itaque est blanditiis aliquam maiores veniam ab!</p>
    <p>Reiciendis cumque fugit earum ea animi et aut molestiae dolores!</p>
</div>

<!-- how to call it -->
<script>
    $(function(){
      
        $('.me').inViewport(
            function(){$(this).addClass("am-in-view");},
            function(){$(this).removeClass("am-in-view");}
        );
      
    });
</script>

【讨论】:

    【解决方案2】:

    你要找的插件叫waypoints

    引自“入门”:

    “假设您有一个带有 overflow:scroll 的 div,并且您希望在此可滚动元素内有一个航点。上下文选项允许您执行此操作。滚动下面的框。”

    $('#example-context').waypoint(function() {
        notify('Hit top of context');
    }, { context: '.example-scroll-div' });
    

    编辑:不使用航路点

    根据你已经做过的,我得出了这个结论:

    function  checkInView(elem,partial)
    {
        var container = $(".scrollable");
        var contHeight = container.height();
        var contTop = container.scrollTop();
        var contBottom = contTop + contHeight ;
     
        var elemTop = $(elem).offset().top - container.offset().top;
        var elemBottom = elemTop + $(elem).height();
    
        var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
        var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;
    
        return  isTotal  || isPart ;
    }
    
    $(document).ready(function(){
    $(".scrollable").scroll(function(){
        var result="",result2="";
       $.each( $(".scrollable p"),function(i,e){
           if (checkInView($(e),false)) {
               $( this ).addClass( "red" );
           } else {
               $( this ).removeClass( "red" );
           }
            result += " " +  checkInView($(e),false);
           result2 += " " +  checkInView($(e),true);
        });
        $("#tt").text(result);
        $("#kk").text(result2);
    });
    });
    .scrollable{
        margin:10px;
        height:100px;
        overflow-y:scroll;
    }
    p
    {
        border-width:1px;
        border-color:black;
        border-style:solid;
    }
    .red {
        background-color: red;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    full:  <div id="tt"></div>
    part: <div id="kk"></div>
    <div class="scrollable">
        <p>item1<span></span></p>
        <p>item2<span></span></p>
        <p>item3<span></span></p>
        <p>item4<span></span></p>
        <p>item5<span></span></p>
        <p>item6<span></span></p>
        <p>item7<span></span></p>
        <p>item8<span></span></p>
    </div>

    【讨论】:

    • 感谢您的回答。我认为它更像是这样 > jsfiddle.net/b63rH 但如果它在视图中,我不知道如何添加一个类。
    【解决方案3】:

    其中offset 是元素与屏幕的偏移量。您应该使用scroll 事件调用它(节流),反复检查元素是否在视图中。

    function isElementInViewport(el, offset){
            var rect = el.getBoundingClientRect();
            offset = offset || 0;
    
            return (
                rect.top - offset >= 0 &&
                rect.left >= 0 &&
                rect.bottom + offset <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
                rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
            );
     }
    

    onscroll 事件一起使用:

    // utilizing underscore's `debounce` method
    $(window).on('scroll.checkVisibility', _.debounce(check, 200));
    
    function check(){
        var visibility = isElementInViewport(element, -100);
        if( visibility )
           // do something if visisble
    
    }
    

    【讨论】:

      【解决方案4】:

      使用Intersection Observer API

      (现代浏览器原生)


      随着 jQuery 逐渐过时,这里有一个使用 Intersection Observer API 的简单解决方案:

      /* Javascript */
      // define an observer instance
      var observer = new IntersectionObserver(onIntersection, {
        root: null, // default is the viewport
        threshold: 0.5, // percentage of taregt's visible area. Triggers "onIntersection"
      });
      
      // callback is called on intersection change
      function onIntersection(entries, opts) {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            // Adding a class name if element is in view
            entry.target.classList.add("class-name");
          } else {
            // Removing the class name if element is NOT in view
            entry.target.classList.remove("class-name");
          }
        });
      }
      
      // Use the bserver to observe an element
      observer.observe(document.getElementById("hello"));
      
      // To stop observing:
      // observer.unobserve(entry.target)
      /* CSS */
      
      #big-div {
        height: 600px;
      }
      
      .class-name {
        background-color: blue;
        transition: 2s background-color;
      }
      <!--HTML-->
      <div id="big-div">Scroll down to see the result!</div>
      <div id="hello">Hello world</div>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-06
        • 1970-01-01
        • 2020-05-29
        • 1970-01-01
        • 2019-12-25
        • 2013-12-04
        • 2015-03-14
        相关资源
        最近更新 更多