最近在开发移动端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; } }