进入下面小程序可以体验效果:
基于官方原版demo加入了回弹动画
WXML:
<scroll-view
class="scroll-area"
type="custom"
scroll-y
show-scrollbar="{{false}}"
worklet:onscrollend="handleScrollEnd"
worklet:onscrollupdate="handleScrollUpdate"
>
<view class="fake-nav-bar" />
<sticky-section push-pinned-header="{{false}}">
<sticky-header>
<view class="search-container">
<view class="search">
<view class="search-icon-wrp">
<image class="search-icon" src="/assets/image/search.png" />
</view>
<view class="search-text">搜索</view>
<view class="search-btn">搜索</view>
</view>
</view>
</sticky-header>
<view>1211111111111111111111111111111111</view>
<view>1211111111111111111111111111111111</view>
</sticky-section>
</scroll-view>
js:
const app = getApp() //这段代码需要放在page页面JS的最顶部
const systemInfo = wx.getSystemInfoSync()
const { shared, Easing,spring ,timing,sequence,delay} = wx.worklet
const lerp = function (begin, end, t) {
'worklet'
return begin + (end - begin) * t
}
const clamp = function (cur, lowerBound, upperBound) {
'worklet'
if (cur > upperBound) return upperBound
if (cur < lowerBound) return lowerBound
return cur
}
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.saftPadding = shared(0)
this.searchBarheight = shared(0)
this.searchBarWidth = shared(100)
this.searchBarLeft = shared(0)
this.navBarOpactiy = shared(1)
this.isTop = shared(false) //是否触顶了
this.isBottom = shared(false) //是否触底了
this.isExc = shared(false) //是否执行动画了
this.isScrolling = shared(false) //是否正在滑动
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
this.applyAnimatedStyle('.nav-bar', () => {
'worklet'
return {
opacity: this.navBarOpactiy.value
}
})
this.applyAnimatedStyle('.search', () => {
'worklet'
return {
width: `${this.searchBarWidth.value}%`,
left: `${this.searchBarLeft.value}%`,
height: `${this.searchBarheight.value}px`
}
})
this.applyAnimatedStyle('.search-container', () => {
'worklet'
return {
backgroundColor: (this.navBarOpactiy.value > 0) ? 'transparent' : '#fff',
paddingTop: `${this.saftPadding.value}px`
}
})
wx.nextTick(()=>{
//胶囊顶部位置(安全位置)
this.saftPadding.value = app.globalData.menu.top
// //胶囊高度
this.searchBarheight.value = app.globalData.menu.height
})
},
handleScrollUpdate(evt) {
'worklet'
const maxDistance = 60
const scrollTop = clamp(evt.detail.scrollTop, 0, maxDistance)
const progress = scrollTop / maxDistance
const EasingFn = Easing.cubicBezier(0.4, 0.0, 0.2, 1.0)
this.searchBarLeft.value = lerp(0, 25, EasingFn(progress))
this.navBarOpactiy.value = lerp(1, 0, progress)
const t1= lerp(100, 45, EasingFn(progress))
if(t1>45&&t1<100){
this.isScrolling.value=true
}
if((t1>45&&t1<100)&&(!this.isExc.value||this.isScrolling.value)){
this.searchBarWidth.value = t1-1.5
}
if(t1===45&&evt.detail.scrollTop>60&&!this.isTop.value){
//靠顶了
this.isTop.value=true
this.isBottom.value=false
this.searchBarWidth.value = t1-2
this.searchBarWidth.value = spring(t1)
this.isExc.value=true
this.isScrolling.value=false
}else if(t1===100&&evt.detail.scrollTop<2&&!this.isBottom.value){
//靠底了
this.isBottom.value=true
this.isTop.value=false
this.searchBarWidth.value = t1-2
this.searchBarWidth.value = spring(t1)
this.isExc.value=true
this.isScrolling.value=false
}
},
handleScrollEnd(evt){
'worklet'
this.isScrolling.value=false
this.isExc.value=false
},
/**
* 生命周期函数--监听页面显示
*/
onShow(){
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
WXSS:
.fake-nav-bar {
height: 60px;
}
.search-container {
padding: 0 16px 10px 16px;
}
.search {
display: flex;
flex-direction: row;
box-sizing: border-box;
width: 100%;
height: 40px;
border-radius: 20px;
border: 2px solid #07c160;
position: relative;
align-items: center;
background-color: #fff;
}
.search-text {
color: #8f8888;
font-size: 14px;
}
.search-icon-wrp {
display: flex;
width: 30px;
height: 100%;
flex-direction: row;
align-items: center;
justify-content: center;
}
.search-icon {
width: 16px;
height: 16px;
}
.search-btn {
position: absolute;
right: 0;
width: 60px;
height: 100%;
border-radius: 20px;
background-color: #07c160;
display: flex;
align-items: center;
justify-content: center;
color: #FFF;
font-size: 16px;
/* font-weight: bold; */
}
.nav-bar {
background-color: #fff;
position: absolute;
}
.nav-left {
display: flex;
flex-direction: row;
align-items: center;
}
.nav-logo {
width: 40px;
height: 40px;
border-radius: 50%;
}
.nav-title {
margin-left: 2px;
font-size: 20px;
color: #3f3e3e;
/* font-weight: bold; */
}
.scroll-area {
height: 100vh;
}