当页面上滑时,顶部当导航需要进行吸顶处理。滑动过程使用scroll事件监听,当滚动的高度到底一定时,便设置样式 absolute:fixed;top:0px;
以吸顶处理。
以上处理在安卓中时完全没有问题的,但是在iOS中缺会出现严重的样式问题:页面滚动过程中并不吸顶。
针对iOS做兼容处理。iOS支持一个特殊的定位方式:absolute:sticky;//粘性定位。
sticky 英文字面意思是粘,粘贴,所以可以把它称之为粘性定位。
position: sticky; 基于用户的滚动位置来定位。
粘性定位的元素是依赖于用户的滚动,在 position:relative 与 position:fixed 定位之间切换。
它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。
元素定位表现为在跨越特定阈值前为相对定位,之后为固定定位。
这个特定阈值指的是 top, right, bottom 或 left 之一,换言之,指定 top, right, bottom 或 left 四个阈值其中之一,才可使粘性定位生效。否则其行为与相对定位相同。
div.sticky {
position: -webkit-sticky; /* Safari */
position: sticky;
top: 0;
background-color: green;
border: 2px solid #4CAF50;
}
const judgeUserAgent = function () {
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
return 'ios'
} else if (/(Android)/i.test(navigator.userAgent)) {
return 'android'
} else {
return 'pc'
}
}
positionSticky (el, top = 0, zIndex = 10) {
const ot = el.offsetTop - top
const fn = () => {
const st = document.body.scrollTop || document.documentElement.scrollTop
const fixStyle = `position: fixed;top: ${top}px;left: 0px;z-index: ${zIndex};`
el.setAttribute('style', st > ot ? fixStyle : '')
}
fn()
document.addEventListener('scroll', fn)
}
注意:安卓的fixed定位需要在滚动时没有问题,但是从relative定位切换到fixed定位后,会脱离文本流,使得切换fixed样式时页面会出现闪烁的情况。
解决办法:在需要的进行fixed定位的dom部分外边使用一个div将其包裹起来,并赋予相应的高度。
<div style="height:50px;">
需要进行定位的dom部分<-->
<div ref="postionDom">
内容<-->
div>
div>
// vue中mounted钩子
mounted () {
const el = this.$refs.postionDom
this.positionSticky(el, 0, 10)
}
positionSticky (el, top = 0, zIndex = 10) {
if (window.screen.height === 812 && window.screen.width === 375) { // 在iphonex中打开
top += 20
}
const fixStyle = `position: -webkit-sticky;position: sticky;top: ${top}px;left: 0px;z-index: ${zIndex};`
el.setAttribute('style', fixStyle)
return
}
需要进行定位的dom部分<-->
<div ref="postionDom">
内容<-->
div>
// vue中mounted钩子
mounted () {
const el = this.$refs.postionDom
this.positionSticky(el, 0, 10)
}
注意:兼容处理依然需要将不同设备类型的代码整合起来,这样易于调用与维护。
最终代码
const judgeUserAgent = function () {
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
return 'ios'
} else if (/(Android)/i.test(navigator.userAgent)) {
return 'android'
} else {
return 'pc'
}
}
const positionSticky = function(el, top = 0, zIndex = 10) {
const userAgent = judgeUserAgent()
if (userAgent === 'ios') {
// 虽然iOS中不需要在dom外边包裹一层,但是为了兼容android。
// 注意,sticky定位元素不能在其外层的dom元素使用div进行包裹起来,否则sticky会失效。定位到parentNode刚好也避过这个坑
el = el.parentNode
if (window.screen.height === 812 && window.screen.width === 375) { // 在iphonex中打开
top += 20
}
const fixStyle = `position: -webkit-sticky;position: sticky;top: ${top}px;left: 0px;z-index: ${zIndex};`
el.setAttribute('style', fixStyle)
return
}
const ot = el.offsetTop - top
const fn = () => {
const st = document.body.scrollTop || document.documentElement.scrollTop
const fixStyle = `position: fixed;top: ${top}px;left: 0px;z-index: ${zIndex};`
el.setAttribute('style', st > ot ? fixStyle : '')
}
fn()
document.addEventListener('scroll', fn)
}
<div style="height:50px;">
需要进行定位的dom部分<-->
<div ref="postionDom">
内容<-->
div>
div>
// vue中mounted钩子
mounted () {
const el = this.$refs.postionDom
this.positionSticky(el, 0, 10)
}