吸顶效果是web开发中一种常见的交互方式,常见的应用场景有导航、搜索框等等。
吸顶元素的初始位置一般靠近页面顶部,但与顶部有一定距离,这块区域放的是最醒目的元素,页面向下滚动超过吸顶元素初始位置时,把吸顶元素固定在顶部
要求吸顶的元素一般是二级导航栏、搜索框、文章标题栏、表头、tab条等等,共同特点是在内容或功能上比较重要,但又不是最重要的元素
这篇文章以vue3顶部导航栏做分析,vue2、jquery、纯js实现需自行变通一下哈,但关键部分已写出
实现方法: 通过滚动事件的触发,判断当前滚动距离是否到达吸顶距离,如果大于则添加吸顶类名,否则移除类名
准备
如果吸顶导航栏与顶部导航栏不一致,需要准备两个导航栏组件,如果一致,则只需准备一个导航栏组件则可
两个导航栏一致
导航栏组件代码,注意有坑!!!!,在代码中已标出,已有解决方案
<script setup>
import {ref} from 'vue';
// vueUse 实现 第三方插件,自行下载
import { useScroll } from '@vueuse/core'
const { y } = useScroll(window);
// //纯js获取滚动距离
// const y = ref(null);
// //注册滚动事件
// window.onscroll = function(){
// y.value = window.scrollY;
// };
// // jquery实现
// $(function() {
// $(window).scroll(function() {
// console.info($(window).scrollTop());
// });
// });
</script>
<template>
<!-- //坑2:滚动到临界位置的时候,页面抖了一下,向上缩了一截。因为`fixed`定位元素脱离文档流,下面的元素上来,所以页面抖了一下,解决方法是添加一个占位元素 -->
<div style="height:78px;width:100px;" v-if="y>78"></div>
<div class="app-header-sticky" :class="{ show: y > 78 }">
<div class="container">
<font-icon :class="'icon-xingxiansg'" :color="'color'" :size="'size'"></font-icon>
</div>
</div>
</template>
<style scoped lang='scss'>
.app-header-sticky {
width: 100%;
height: 80px;
//超出滚动距离,添加定位
//&表示继承父级样式,
//坑1:这里的父级样式是在style上,不是元素标签哈,比如,这里&表示的是.app-header-sticky
&.show {
position: fixed;
left: 0;
top: 0;
z-index: 999;
}
.container {
display: flex;
align-items: center;
.color {color:red;}
.size {font-size:60px;}
}
}
</style>
页面index.vue码:
<script setup>
import nav from './components/nav.vue'
</script>
<template>
<!-- 导航栏 -->
<nav />
</template>
两个导航栏不一致
原有导航栏不做任何操作,以下是吸顶导航栏操作
<script setup>
import {ref} from 'vue';
// vueUse 实现 vueuse是第三方工具,需自行下载哈
import { useScroll } from '@vueuse/core'
const { y } = useScroll(window);
// //纯js获取滚动距离
// const y = ref(null);
// //注册滚动事件
// window.onscroll = function(){
// y.value = window.scrollY;
// };
// // jquery获取滚动距离
// $(function() {
// $(window).scroll(function() {
// console.info($(window).scrollTop());
// });
// });
</script>
<template>
//如果滚动距离大于78,则添加新类名show
<div class="app-header-sticky" :class="{ show: y > 78 }">
<div class="container">
<font-icon :class="'icon-xingxiansg'" :color="'color'" :size="'size'"></font-icon>
</div>
</div>
</template>
<style scoped lang='scss'>
//先隐藏,后显现
.app-header-sticky {
width: 100%;
height: 80px;
position: fixed;
left: 0;
top: 0;
z-index: 999;
background-color: #fff;
border-bottom: 1px solid #e4e4e4;
// 此处为关键样式!!!
// 状态一:往上平移自身高度 + 完全透明 ---方便实现渐变效果,更加平滑
transform: translateY(-100%);
opacity: 0;
// 状态二:移除平移 + 完全不透明
//&表示继承父级样式,
//坑:这里的父级样式是在style上,不是元素标签哈,比如,这里&表示的是.app-header-sticky
&.show {
transition: all 0.3s linear;
transform: none;
opacity: 1;
}
.container {
display: flex;
align-items: center;
.color {color:red;}
.size {font-size:60px;}
}
}
</style>
页面index.vue代码:
<script setup>
//原有导航栏
import nav from './components/nav.vue'
//吸顶导航栏
import fixed from './components/fixed.vue'
</script>
<template>
<nav />
<fixed />
</template>
ios不完整方案
以上两种方案在移动IOS是行不通的,吸顶定位方法的改为position:sticky;
吸顶时Css写法:
&.show {
position: sticky;
left: 0;
top: 0;
z-index: 999;
}
虽然将定位方式做了更改,但IOS还是存在一些问题,这些问题是因为 IOS对scroll做了很大的限制:
手指划动屏幕 -> 滚动 -> 手指抬起 -> 惯性滚动 -> 停止滚动
整个过程,直到停止滚动时才会触发1次scroll事件,也就是说,IOS8以下的scroll变成了scrollend。监听滚动判断位置的方法完全失效,平滑吸顶效果变成了滚过临界位置直到停止滚动时,吸顶元素跳到目标位置,无法实时获取吸顶状态,体验非常差,position:sticky;也无法解决这个问题
目前笔者还没有找到解决方案,如有新思路、好点子,或者成熟方案,麻烦告知,感激不尽