最近在开发移动端H5页面时,遇到渐变导航的需求点,想了两种方案,在此记录下~

总的来说,渐变导航分为两种(仅仅在我看来哈),一种是 渐变进度可人为控制,另一种是渐变进度不可控。

 

可人为控制 的意思是:你可以按住屏幕慢慢滚动并在此过程中任意停留,在任意停留点中你可以看到当前渐变程度和效果,并且在你停留的这个点,渐变效果不会发生改变,当再次滚动时渐变程度才会有所变化。它的原理就是:通过监听页面滚动的 scrollTop 值,在不同的 scrollTop值范围中,给导航的容器元素对应设置不同的 opacity。

 

不可控 的意思是:当页面滚动到某个值时就触发导航样式变化,就算你停下滚动,他也会自动渐变完整个效果。

它的原理就是:当页面滚动到某个值,就设置新的样式,并且通过transition做过度处理。

 

可人为控制渐变进度



state = {
isScroll: false,
headerOpacity: 1,
}



componentDidMount() {
document.documentElement.scrollTop = 0
document.body.scrollTop = 0
window.pageYOffset = 0
const {dispatch} = this.props
dispatch(getHottestTopList({limit: 50}))
window.addEventListener('scroll', this.onScroll, getListenerOptions())
}

componentWillUnmount() {
window.removeEventListener('scroll', this.onScroll, getListenerOptions())
}



onScroll = evt => {
const scrollTop = Math.max(
window.scrollY,
document.documentElement.scrollTop
)
if (scrollTop >= 40) {
this.setState({isScroll: true, headerOpacity: 1})
} else if (scrollTop >= 35) {
this.setState({isScroll: true, headerOpacity: 0.8})
} else if (scrollTop >= 30) {
this.setState({isScroll: true, headerOpacity: 0.6})
} else if (scrollTop >= 25) {
this.setState({isScroll: true, headerOpacity: 0.4})
} else if (scrollTop >= 20) {
this.setState({isScroll: true, headerOpacity: 0.2})
} else {
this.setState({isScroll: false, headerOpacity: 1})
}
}


 

HTML:



<FullscreenHeaderWrap
className={cx('GroupHottestList__HeaderWrap', {
'GroupHottestList__HeaderWrap--scroll': isScroll,
})}
style={{opacity: headerOpacity}}
>
<div className="GroupHottestList__Header">
<div
className="GroupHottestList__Header__btnBack"
role="button"
tabIndex={0}
onClick={() => {
closeWindow()
}}
/>
<span className="GroupHottestList__Header__title">社团最燃榜</span>
<div className="GroupHottestList__Header__iconBtnWrap">
<div
className="GroupHottestList__Header__btnRule"
role="button"
tabIndex={0}
onClick={() => {
openUrl({
url: `${
window.location.origin
}/hybrid/topic/groupHottestRule`,
})
}}
>
榜单规则
</div>
<div
className="GroupHottestList__Header__btnShare"
role="button"
tabIndex={0}
onClick={this.toShare}
/>
</div>
</div>
</FullscreenHeaderWrap>


CSS



&__HeaderWrap {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: transparent;
z-index: 1;
&--scroll {
background-color: #fff;
.GroupHottestList__Header__btnBack {
background: url("./images/back-black.png") no-repeat center center / 100% 100% transparent;
}
.GroupHottestList__Header__title {
color: #242529;
}
.GroupHottestList__Header__btnRule {
background: #FFFFFF;
color: #999EAD;
border: 1px solid #F3F3F9;
}
.GroupHottestList__Header__btnShare {
background: url("./images/share-black.png") no-repeat center center / 100% 100% transparent;
}
}
}
&__Header {
width: 100%;
height: 44px;
padding: 0 16px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
&__btnBack {
width: 24px;
height: 24px;
background: url("./images/back-white.png") no-repeat center center / 100% 100% transparent;
}
&__title {
font-style: normal;
font-weight: 500;
font-size: 18px;
line-height: 25px;
color: #FFFFFF;
}
&__iconBtnWrap {
display: flex;
align-items: center;
position: relative;
}
&__btnRule {
width: 70px;
height: 24px;
background: rgba(255, 255, 255, 0.1);
border-radius: 22px;
box-sizing: border-box;
text-align: center;
line-height: 24px;
font-style: normal;
font-weight: normal;
font-size: 13px;
color: #FFFFFF;
position: absolute;
top: 0;
left: -82px;
}
&__btnShare {
width: 24px;
height: 24px;
background: url("./images/share-white.png") no-repeat center center / 100% 100% transparent;
}
}


 

不可控渐变进度



state = {
isScroll: false,
}


componentDidMount() {
document.documentElement.scrollTop = 0
document.body.scrollTop = 0
window.pageYOffset = 0
const {dispatch} = this.props
dispatch(getHottestTopList({limit: 50}))
window.addEventListener('scroll', this.onScroll, getListenerOptions())
}

componentWillUnmount() {
window.removeEventListener('scroll', this.onScroll, getListenerOptions())
}


onScroll = evt => {
const scrollTop = Math.max(
window.scrollY,
document.documentElement.scrollTop
)
if (scrollTop >= 25) {
this.setState({isScroll: true})
} else {
this.setState({isScroll: false})
}
}


 

HTML



<FullscreenHeaderWrap
className={cx('GroupHottestList__HeaderWrap', {
'GroupHottestList__HeaderWrap--scroll': isScroll,
})}>
<div className="GroupHottestList__Header">
<div
className="GroupHottestList__Header__btnBack"
role="button"
tabIndex={0}
onClick={() => {
closeWindow()
}}
/>
<span className="GroupHottestList__Header__title">社团最燃榜</span>
<div className="GroupHottestList__Header__iconBtnWrap">
<div
className="GroupHottestList__Header__btnRule"
role="button"
tabIndex={0}
onClick={() => {
openUrl({
url: `${
window.location.origin
}/hybrid/topic/groupHottestRule`,
})
}}
>
榜单规则
</div>
<div
className="GroupHottestList__Header__btnShare"
role="button"
tabIndex={0}
onClick={this.toShare}
/>
</div>
</div>
</FullscreenHeaderWrap>


 

CSS



&__HeaderWrap {
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: transparent;
transition: background-color 0.2s ease-out;
z-index: 1;
&--scroll {
transition: background-color 0.5s ease-in; // 先慢后快
background-color: #fff;
.GroupHottestList__Header__btnBack {
background: url("./images/back-black.png") no-repeat center center / 100% 100% transparent;
}
.GroupHottestList__Header__title {
color: #242529;
}
.GroupHottestList__Header__btnRule {
background: #FFFFFF;
color: #999EAD;
border: 1px solid #F3F3F9;
}
.GroupHottestList__Header__btnShare {
background: url("./images/share-black.png") no-repeat center center / 100% 100% transparent;
}
}
}
&__Header {
width: 100%;
height: 44px;
padding: 0 16px;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
&__btnBack {
width: 24px;
height: 24px;
background: url("./images/back-white.png") no-repeat center center / 100% 100% transparent;
}
&__title {
font-style: normal;
font-weight: 500;
font-size: 18px;
line-height: 25px;
color: #FFFFFF;
}
&__iconBtnWrap {
display: flex;
align-items: center;
position: relative;
}
&__btnRule {
width: 70px;
height: 24px;
background: rgba(255, 255, 255, 0.1);
border-radius: 22px;
box-sizing: border-box;
text-align: center;
line-height: 24px;
font-style: normal;
font-weight: normal;
font-size: 13px;
color: #FFFFFF;
position: absolute;
top: 0;
left: -82px;
}
&__btnShare {
width: 24px;
height: 24px;
background: url("./images/share-white.png") no-repeat center center / 100% 100% transparent;
}
}