在浏览器及 Rax 中实现吸顶效果,position sticky 属性的应用及监听页面滚动(React)实现吸顶效果
最近遇到了移动端小程序需要实现吸顶效果的需求,就是 tab 页抬头滑动到页面顶部时需要固定到页面的顶部不再滚动。这里介绍两种实现方式,当然这两种方式在浏览器同样适用,以下思路仅供参考,实际效果以实际操作为准。
1. position: sticky 定位实现
CSS 的 position 属性用于指定一个元素在文档中的定位方式,我们常用的值包括 static(默认),fixed,relative,absolute.sticky 五种。top,right,bottom 和 left 属性则决定了该元素的最终位置。
这里对其他四种不做过多介绍,很多文章都已经详尽的介绍了他们的用法含义,这里我们直接来说 sticky 粘性定位。
元素设置了 position: sticky 后,根据正常文档流进行定位,然后相对它的最近滚动祖先(nearest scrolling ancestor)和 containing block (最近块级祖先 nearest block-level ancestor),包括 table-related 元素,基于 top, right, bottom, 和 left 的值进行偏移。偏移值不会影响任何其他元素的位置。
该值总是创建一个新的层叠上下文(stacking context)。注意,一个 sticky 元素会“固定”在离它最近的一个拥有“滚动机制”的祖先上(当该祖先的 overflow 是 hidden, scroll, auto, 或 overlay 时),即便这个祖先不是最近的真实可滚动祖先。这有效地抑制了任何“sticky”行为(详情见 Github issue on W3C CSSWG)。
虽说这个属性简单好用,但是呢兼容性问题不容忽视,也不是想用就能用的,由于我是需要在移动端钉钉小程序实现吸顶效果,sticky 属性在钉钉中不兼容,所以只能使用第二种方式。
2. 监听页面滚动,达到滚动高度后修改目标元素 position 属性为 fixed 实现定位效果
思路很简单,就是监听页面滚动,页面滚动指定距离后,修改元素的 position 为 fixed ,配合 top 属性达到固定效果。
在 Rax 跨端小程序中示例代码如下
import { createElement, useEffect } from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import { isMiniApp } from 'universal-env';
import { registerNativeEventListeners, addNativeEventListener, removeNativeEventListener } from 'rax-app';
function Index() {
const [needFixed, setNeedFixed] = useState(false);
function handlePageScroll(scroll) {
if(scroll.top >= 100){
setNeedFixed(true);
}else{
setNeedFixed(false);
}
}
useEffect(() => {
if(isMiniApp) {
// 开始监听 onPageScroll 事件
addNativeEventListener('onPageScroll', handlePageReachBottom);
}
return () => {
if (isMiniApp) {
// 移除 onPageScroll 事件的监听器
removeNativeEventListener('onPageScroll', handlePageReachBottom);
}
}
}, []);
return (
<View style={{position:needFixed?"fixed":"static",top:0}}>
<Text>1</Text>
</View>
);
}
if (isMiniApp) {
registerNativeEventListeners(Index, ['onPageScroll']);
}
export default Index;
在浏览器中 React 示例代码如下
export default function ScrollFixed(props: any) {
const [needFixed, setNeedFixed] = useState(false);
const styleObj: CSSProperties = {
width: '100%',
position: needFixed ? 'fixed' : 'relative',
top: 0,
zIndex: 100,
};
useEffect(() => {
window.onscroll = function () {
const scrollTop = document.documentElement.scrollTop;
if (scrollTop > 110 && !needFixed) {
setNeedFixed(true);
} else if(scrollTop <= 110) {
setNeedFixed(false);
}
};
}, []);
return (
<div className={props.className} style={styleObj}>
{props.children}
</div>
);
}
上面的 ScrollFixed 组件就是监听的页面 scroll 时间,当滑动距离大于 110 且 当前元素未固定时,设置固定状态,否则不固定。