根据用户在 Angular 页面上的滚动位置使特定标题保持粘性

Posted

技术标签:

【中文标题】根据用户在 Angular 页面上的滚动位置使特定标题保持粘性【英文标题】:Make specific header sticky depending on user's scroll position on page in Angular 【发布时间】:2018-08-28 13:27:30 【问题描述】:

在 Angular 中,我需要根据用户的滚动位置在页面上的位置设置面板标题。

我相信有两种方法可以实现我想要实现的目标。其中之一是纯 css 使用 position: sticky。你可以在 app.component.css 中看到我注释掉的 css 代码。这种技术与 Angular 无关,并且会起作用。

另一种更符合浏览器的方式是使用 javascript,这是我在使用 Angular 与普通 html/css/js 时遇到的困难。

使用 Angular 我正在使用 @HostListener 来访问窗口滚动。这使我可以访问当前窗口滚动位置。我相信这是一个很好的起点。

我无法弄清楚的部分是如何使用 offsetTop() 检查每个面板标题的位置,如果正在检查的面板标题的位置小于我要添加粘性类的滚动位置,否则删除它。

事实上,我知道如果我将面板作为它自己的组件,这会更容易一些。但是,目前这不是一个选项。

请在以下地址查看我目前所拥有的信息:https://stackblitz.com/edit/angular-b7pgrx

【问题讨论】:

【参考方案1】:

Follow me headers - 这就是您想要的特色。

Chris Spittles 已经有一个很好的工作代码笔: https://codepen.io/chrissp26/pen/gBrdo

万一有一天链接失效:

html:

<h1>Multiple Sticky Titles with CSS and JS</h1>
<section class="explanation">
  <p>On some mobile platforms there are lists that group items under multiple headings. As you scroll through the list, the current title or heading follows you until you reach the next one at which point the current one is pushed up and the new title or heading docks to the top. <br>This snippet emulates this functionality.</p>
  <p>
    I created this originally because of this
    <a href="http://***.com/questions/13279725/getting-a-sticky-header-to-push-up-like-in-instagrams-iphone-app-using-css-a/13293684#13293684" target="_blank">question</a> on stack overflow.
  </p>

</section>

<div class="followMeBar">A</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">B</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="followMeBar">C</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>

css:

.followMeBar 
  background: #e64a19;
  padding: 10px 20px;
  position: relative;
  z-index: 1;
  color: #fff;


.followMeBar.fixed 
  position: fixed;
  top: 0;
  width: 100%;
  box-sizing: border-box;
  z-index: 0;


.followMeBar.fixed.absolute 
  position: absolute;



/* For aesthetics only ------------------------------------------------------------------*/

body 
  margin: 0;
  font-family: Segoe, "Segoe UI", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif;


h1 
  font: 200 1.2em "Segoe UI Light", "DejaVu Sans", "Trebuchet MS", Verdana, sans-serif;
  font-weight: 200;
  color: #fff;
  background: #039be4;
  padding: 20px;
  margin: 0;
  border-bottom: 10px solid #ccc;
  strong 
    font-family: "Segoe UI Black";
    font-weight: normal;
  


.explanation 
  padding: 20px;
  max-width: 600px;
  p 
    max-width: 300px;
    color: #fff;
    font-size: 0.8rem;
  

JavaScript:

var stickyHeaders = (function() 

  var $window = $(window),
      $stickies;

  var load = function(stickies) 

    if (typeof stickies === "object" && stickies instanceof jQuery && stickies.length > 0) 

      $stickies = stickies.each(function() 

        var $thisSticky = $(this).wrap('<div class="followWrap" />');

        $thisSticky
            .data('originalPosition', $thisSticky.offset().top)
            .data('originalHeight', $thisSticky.outerHeight())
              .parent()
              .height($thisSticky.outerHeight());             
      );

      $window.off("scroll.stickies").on("scroll.stickies", function() 
          _whenScrolling();     
      );
    
  ;

  var _whenScrolling = function() 

    $stickies.each(function(i)             

      var $thisSticky = $(this),
          $stickyPosition = $thisSticky.data('originalPosition');

      if ($stickyPosition <= $window.scrollTop())         

        var $nextSticky = $stickies.eq(i + 1),
            $nextStickyPosition = $nextSticky.data('originalPosition') - $thisSticky.data('originalHeight');

        $thisSticky.addClass("fixed");

        if ($nextSticky.length > 0 && $thisSticky.offset().top >= $nextStickyPosition) 

          $thisSticky.addClass("absolute").css("top", $nextStickyPosition);
        

       else 

        var $prevSticky = $stickies.eq(i - 1);

        $thisSticky.removeClass("fixed");

        if ($prevSticky.length > 0 && $window.scrollTop() <= $thisSticky.data('originalPosition') - $thisSticky.data('originalHeight')) 

          $prevSticky.removeClass("absolute").removeAttr("style");
        
      
    );
  ;

  return 
    load: load
  ;
)();

$(function() 
  stickyHeaders.load($(".followMeBar"));
);

【讨论】:

Megajin 谢谢,我没有意识到 followme headers 是功能的名称。这将有助于我做进一步的研究。但是,我的问题具体是如何在没有 jQuery 的情况下在 Angular 中做到这一点。在我发布的 stackblitz 中,我离我不远了。

以上是关于根据用户在 Angular 页面上的滚动位置使特定标题保持粘性的主要内容,如果未能解决你的问题,请参考以下文章

动画滚动到滚动上的特定页面位置

如何在页面上的特定滚动位置启动功能?

Angular 6:如何根据滚动突出显示导航栏上的元素?

如何在滚动的特定部分添加类

如何使滚动视图上的页面自动旋转?

长数组列表渲染使 Angular.js 中的页面滚动变慢