导航栏吸顶

当页面滚动超过导航栏时,导航栏依附固定在页面顶端

下面介绍两种方式吧, 一种是 position: sticky, 另一种是getBoundingClientRect()

position: sticky 实现

.stickyPostion {
    postion: sticky;
    top: 0;
}

使用条件:

  • 父元素不能overflow:hidden或者overflow:auto属性。
  • 必须指定topbottomleftright4个值之一,否则只会处于相对定位
  • 父元素的高度不能低于sticky元素的高度
  • sticky元素仅在其父元素内生效

sticky 坑

  • 兼容性不太好
  • 不能触发 BFC

getBoundingClientRect()

getBoundingClientRect用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
getBoundingClientRect是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)

  • 获取当前 nav 到浏览器顶端的距离。
  • 直接监听scroll 事件,
  • 用div包裹住nav导航栏,我们只需要获取当前div到顶端的距离即可,等到时 top值为0的时候,设置子级的position:fixed, 还原只需取消掉子级的position即可
    • 如果没有用div 包裹 nav导航栏的话,等top 值为0,就无法还原了,position 一直为fix, getBoundingClientRect.top值一直为0;

结构应该如下:

<div ref={this.stickyRef} id="sticky">
    <div className={isFixed ? styles.fix : styles.static}> // 这个为nav
        <div>吸顶效果</div>
    </div>
</div>
componentDidMount() {
    const top = this.stickyRef.current.getBoundingClientRect().top;
    this.setState({
        initPostionTop: top
    })
    window.addEventListener('scroll', this.handleScroll);
}
handleScroll = (e) => {
    const { isFixed, initPostionTop } = this.state
    const scrollTop = e.srcElement.body.scrollTop || e.srcElement.documentElement.scrollTop;
    // 这里做了个优化,防止频繁setState, 如果一开始为吸顶,以及滚动距离大于 nav 到顶部的距离的时候,
    // 或者 (不吸顶同时当前滚动距离小于nav到顶部的距离时)我们操作
    if(isFixed && scrollTop >= initPostionTop || !isFixed && scrollTop <= initPostionTop) {
        return ;
    }  else  {
        this.setState({
            isFixed: scrollTop > initPostionTop
        })
    }
}

小程序 (我使用的是Taro)

小程序不支持 window.addEventListener('scroll', this.handleScroll);,只有onPageScroll

下面是官方说明
注意:请只在需要的时候才在 page 中定义此方法,不要定义空方法。以减少不必要的事件派发对渲染层-逻辑层通信的影响。注意:请避免在 onPageScroll 中过于频繁的执行 this.setState() 等引起逻辑层-渲染层通信的操作。尤其是每次传输大量数据,会影响通信耗时。

taro获取节点有点坑

componentDidMount() {
    // 注意this.$scope
    const query = Taro.createSelectorQuery().in(this.$scope);
    query.select('#sticky').boundingClientRect((rect) => {
        this.setState({
            initPostionTop: rect.top
        })
    }).exec();
}

onPageScroll 代码基本一样

  • 这种方式有个坑,当吸顶的一瞬间,会发生抖动,这是因为 position变成fixed 的时候脱离了文档流。
    解决方案是 在postion:fixed;的元素里添加transform: translateZ(0);,我想应该是开启gpu 渲染,所以变得顺滑了吧

关于优化

h5 优化,可以用另一种方式,就是用 监听滚动的时候使用 节流, 可以用 lodash.throttle

window.addEventListener('scroll', _.throttle(self.handleScrollThree, 50));

效果

b8827be2b9af0f70b7b9e3e9838e30e6.gif