因为项目需求,最近开始转到微信公众号开发,接触到了vue框架,这个效果的实现虽说是基于vue框架下实现的,但是同样也可以借鉴到其他地方,原理都是一样的。
其实js做这个效果还是挺简单的,因为在css中我们可以设置一个元素的position: fixed;
,这样它就可以固定在那里,这样不管页面怎么滚动,它的位置都不受影响,所以我们的思路就是在合适的时机把要吸顶的头部元素的position属性设置为fixed就可以了。但是这个合适的时机是什么时候呢,这就需要我们计算了,我们需要监听页面的滚动状态,当页面滚动到要吸顶元素所处的位置的时候就是我们设置它固定的时候,所以就需要我们:
在mounted回调中加入以下代码:
mounted() { // handlescroll为页面滚动的监听回调 window.addeventlistener('scroll', this.handlescroll); },
同时在destroyed回调中移除监听:
destroyed(){ window.removeeventlistener('scroll', this.handlescroll); },
计算出来这个距离之后就可以确定固定吸顶元素的时机了,如果你的吸顶元素上面的元素的高度是固定的话,那就简单了,直接在handlescroll方法中进行判断就可以了,可以直接跳到第三步了,如果是动态的,那就需要我们在接口请求完数据,dom元素渲染完之后进行动态计算了,vue中有一个很好用的方法,可以很方便的监听dom渲染完成:
// 监听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); });
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,非常方便:
<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>
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>
<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>
如对本文有疑问, 点击进行留言回复!!
web前端基础之HTML5语义化新标签学习笔记(8)学会用语义化标签
网友评论