Vue开发——实现吸顶效果

由于项目需求,最近开始转到微信公众号开发,接触到了Vue框架,这个效果的实现虽然说是基于Vue框架下实现的,可是一样也能够借鉴到其余地方,原理都是同样的。css

进入正题,先看下效果图:

吸顶效果
其实js作这个效果仍是挺简单的,由于在css中咱们能够设置一个元素的 position: fixed;,这样它就能够固定在那里,这样无论页面怎么滚动,它的位置都不受影响,因此咱们的思路就是在合适的时机把要吸顶的头部元素的position属性设置为fixed就能够了。可是这个合适的时机是何时呢,这就须要咱们计算了,咱们须要监听页面的滚动状态,当页面滚动到要吸顶元素所处的位置的时候就是咱们设置它固定的时候,因此就须要咱们:

1.监听页面的滚动状态:

在mounted回调中加入如下代码:ios

mounted() {
  // handleScroll为页面滚动的监听回调
  window.addEventListener('scroll', this.handleScroll);
 },
复制代码

同时在destroyed回调中移除监听:浏览器

destroyed(){
  window.removeEventListener('scroll', this.handleScroll);
},
复制代码

2.计算吸顶元素到页面顶部的距离:

计算出来这个距离以后就能够肯定固定吸顶元素的时机了,若是你的吸顶元素上面的元素的高度是固定的话,那就简单了,直接在handleScroll方法中进行判断就能够了,能够直接跳到第三步了,若是是动态的,那就须要咱们在接口请求完数据,dom元素渲染完以后进行动态计算了,Vue中有一个很好用的方法,能够很方便的监听dom渲染完成:bash

// 监听dom渲染完成
this.$nextTick(function(){
  // 这里fixedHeaderRoot是吸顶元素的ID
  let header = document.getElementById("fixedHeaderRoot");
  // 这里要获得top的距离和元素自身的高度
  this.offsetTop = header.offsetTop;
  this.offsetHeight = header.offsetHeight;
  console.log("offsetTop:" + this.offsetTop + "," + this.offsetHeight);
});
复制代码

3.判断页面滚动距离:

handleScroll(){
  // 获得页面滚动的距离
  let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
  // 判断页面滚动的距离是否大于吸顶元素的位置
  this.headerFixed = scrollTop > (this.offsetTop - this.offsetHeight * 2);
},
复制代码

ps:这里理论上其实应该是scrollTop > (this.offsetTop - this.offsetHeight),可是不知道为啥我这里作出来后滚动到吸顶元素位置的时候scrollTop仍是比this.offsetTop - this.offsetHeight的值小,因此这里*2,这样得出来的值才刚恰好,若是有知道的朋友能够帮忙解惑一下。微信

上面咱们获得了一个headerFixed的boolean属性值,接下来咱们只须要根据它的值来设置吸顶元素的position: fixed;属性就能够了。 咱们能够写一个css样式:框架

.isFixed{
  position: fixed;
  top: px2rem(110);
  left: px2rem(20);
  right: px2rem(20);
}
复制代码

而后Vue能够在dom元素里这样动态设置class,很是方便:dom

<div id="fixedHeaderRoot">
  <div id="knowPointHeader" class="knowPointHeader" :class="headerFixed?'isFixed':''">
    <div><span>知识模块</span></div>
    <div><span>知识点</span></div>
    <div><span>能力要求</span></div>
  </div>
</div>
复制代码

其实到这里这个效果已经实现完成了,不过我在测试过程当中发现,由于ios手机页面滚动到底部的时候,还能够上拉,有一个橡皮筋效果,这个效果会致使一个咱们页面的一个Bug,由于它的这种橡皮筋效果也会触发页面滚动的监听,当数据不少的时候其实看不出来,只有当数据恰好占满屏幕的时候,这个时候你再继续往上滑动屏幕,就会触发页面的滚动监听,这个时候handleScroll方法中计算出来的值scrollTop是大于吸顶元素top的距离,因此吸顶元素会被设置为固定属性,你们知道一个元素一旦被设置为position: fixed;,那么它就会相对于浏览器窗口进行定位,这样咱们下面的内容就会往上顶,这样的话scrollTop的值又小于了吸顶元素top的距离,这样headerFixed属性又为false,position: fixed;属性又没有了,这样它就又相对与它本来的父元素进行定位,这样就成了一个循环,你会发现页面会上下跳到,这样是确定不行的,因此我下面又针对这个问题进行了一个优化,固然这个方案感受不是特别完美,不过确实能够解决这个问题。

经过上面的分析咱们能够得知形成这个问题的缘由是由于咱们把设置了元素的position: fixed;属性,使得下面的内容往上顶,因此要想解决这个问题,那咱们就不固定这个元素,可是这样的话就达不到吸顶的效果了,因此咱们须要再加一个和吸顶元素如出一辙的元素,它一直就是固定状态:

<div id="fixedHeaderRootReal">
  <div class="knowPointHeader isFixed" v-show="headerFixed">
    <div><span>知识模块</span></div>
    <div><span>知识点</span></div>
    <div><span>能力要求</span></div>
  </div>
</div>
复制代码

这个元素默认是隐藏的,只有当页面滚动的距离达到了它的位置的时候咱们才让它显示,因为它是固定状态,因此它的隐藏显示并不会对页面产生影响,这样下面的内容就不会往上顶了,就能够解决ios手机上拉页面橡皮筋效果的Bug了,固然这种方式有些取巧,可是暂时没有更好的解决方案了,若是你们有更好的解决方案,欢迎在下面评论。最后给你们看一下个人页面布局:

<div v-show="kpointListShow" class="knowPointList">
      <div id="fixedHeaderRoot">
        <div id="knowPointHeader" class="knowPointHeader">
          <div><span>知识模块</span></div>
          <div><span>知识点</span></div>
          <div><span>能力要求</span></div>
        </div>
      </div>
      <div id="fixedHeaderRootReal">
        <div class="knowPointHeader isFixed" v-show="headerFixed">
          <div><span>知识模块</span></div>
          <div><span>知识点</span></div>
          <div><span>能力要求</span></div>
        </div>
      </div>
      <div class="knowPointItem" v-for="(kpointItem,index) in rows.kpointList" :key="index">
        <div><span>{{kpointItem.knowModule}}</span></div>
        <div><span>{{kpointItem.knowPoint}}</span></div>
        <div><span>{{kpointItem.abilityRequire}}</span></div>
      </div>
</div>
复制代码

参考布局

喜欢的麻烦动动小手点个赞来支持我,有不对的地方欢迎你们指正,有什么问题也能够在下方留言,我看到后会第一时间回复!谢谢您来看这篇文章!🌹🌹🌹

相关文章
相关标签/搜索