Vue导航栏吸顶切换功能实现,兼容px2rem-loader自动转rem
最上面的ad-show在实际项目中可以用来做商品或者广告轮播,下面
设置了三个区域块,分别为onePage,twoPage和threePage,在实际项目中可以用作商品详情,物流说明,注意事项等。
在阅读代码之前,感兴趣的童鞋可以先了解一下clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop的区别。这样才能明白代码的计算方式和获取元素节点高度的方式。
附上他人博客链接,写的不错,可以提前阅读一下帮助理解此篇内容:https://blog.csdn.net/qq_35430000/article/details/80277587
如果木有时间阅读,木有关系,我大概总结了一下:
- 网页可见区域高:document.body.clientHeight
- 网页正文全文高:document.body.scrollHeight
- 网页可见区域高(包括边线的高):document.body.offsetHeight
- 网页被卷去的高:document.body.scrollTop
- 屏幕分辨率高:window.screen.height
- 节点高度(包含padding和border):this.$refs.scrollTwo.offsetTop
-
节点高度(包含padding,但不包含border):this.$refs.scrollTwo.clientHeight
严谨起见,我采用了offsetTop来获取节点自己的高度
因为高度都是动态获取的元素高度,所以不必担心项目用了px2rem-loader把px都自动转成了rem
微信图片_20201127143453.jpg
<template>
<div id="needscroll" class="hello">
<div class="ad-show">
<p>展示图</p>
</div>
<div class="onePage" ref="scrollOne">区域一</div>
<div class="twoPage" ref="scrollTwo">区域二</div>
<div class="threePage" ref="scrollThree">区域三</div>
<div class="home-menu" ref="menuHome" v-if="showMenu">
<p :class="{ active: active === 1 }" @click="changeActive(1)">区域一</p>
<p :class="{ active: active === 2 }" @click="changeActive(2)">区域二</p>
<p :class="{ active: active === 3 }" @click="changeActive(3)">区域三</p>
</div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
active: 1,
rememberScroll: 0,
showMenu: false,
scroll1: 0,
scroll2: 0,
scroll3: 0,
isScroll: false,
menuHeight: 0,
};
},
methods: {
getScroll() {
let scrollTop =
window.pageYOffset ||
document.documentElement.scrollTop ||
document.body.scrollTop;
let scrollT1 = this.$refs.scrollOne.offsetTop;
this.scroll1 = scrollT1;
let scrollT2 = this.$refs.scrollTwo.offsetTop;
this.scroll2 = scrollT2;
let scrollT3 = this.$refs.scrollThree.offsetTop;
this.scroll3 = scrollT3;
//这里之所以加了一层判断,是因为menuHome刚开始为隐藏状态,$refs获取为undefined
if (this.$refs.menuHome) {
let space = this.$refs.menuHome.scrollHeight;
if (scrollTop >= scrollT1 - space - 10) {
this.showMenu = true;
} else {
this.showMenu = false;
}
} else {
if (scrollTop >= scrollT1 - 60) {
this.showMenu = true;
} else {
this.showMenu = false;
}
}
},
changeActive(val) {
this.isScroll = true;
this.active = val;
let scrolly = 0;
let space = this.$refs.menuHome.scrollHeight;
if (val === 1) {
scrolly = this.scroll1 - space;
} else if (val === 2) {
scrolly = this.scroll2 - space;
} else {
scrolly = this.scroll3 - space;
}
//这里之所以不用这个方法,是因为真机没有动画效果,但在PC浏览器是有的
// window.scrollTo({
// top: scrolly,
// behavior: "smooth",
// });
this.smoothScroll(0, scrolly, 500);
},
smoothScroll(endX, endY, duration) {
let startX = window.scrollX || window.pageXOffset,
startY = window.scrollY || window.pageYOffset,
distanceX = endX - startX,
distanceY = endY - startY,
startTime = new Date().getTime();
// Easing function
let easeInOutQuart = function (time, from, distance, duration) {
if ((time /= duration / 2) < 1)
return (distance / 2) * time * time * time * time + from;
return (-distance / 2) * ((time -= 2) * time * time * time - 2) + from;
};
let timer = window.setInterval(function () {
let time = new Date().getTime() - startTime,
newX = easeInOutQuart(time, startX, distanceX, duration),
newY = easeInOutQuart(time, startY, distanceY, duration);
if (time >= duration) {
window.clearInterval(timer);
}
window.scrollTo(newX, newY);
}, 1000 / 60); // 60 fps
},
},
mounted() {
window.addEventListener("scroll", this.getScroll);
},
destroyed(){
//不要忘记移除掉监听,否则跳转到其他页面会报错的
window.removeEventListener('scroll',this.getScroll)
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.hello {
.ad-show {
width: 100%;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
background: crimson;
}
.onePage {
width: 100%;
height: 500px;
text-align: center;
background: palegoldenrod;
}
.twoPage {
width: 100%;
height: 400px;
text-align: center;
background: powderblue;
}
.threePage {
width: 100%;
height: 400px;
text-align: center;
background: peachpuff;
}
.home-menu {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 50px;
background: white;
z-index: 999;
display: flex;
flex-direction: row;
p {
flex: 1;
height: 50px;
text-align: center;
line-height: 50px;
font-size: 14px;
}
}
.active {
color: lightsalmon;
background: rgb(247, 247, 247);
}
}
我本来想实现滑动到每个区域时,导航栏会自动选择某个区域,但是在scroll的监听方法里面写,快速点击时会产生交叠问题,此功能还会后续优化,有好想法的童鞋欢迎提出你的宝贵意见,以帮助我更好的完善这个功能
网友评论