你是否也收到这样的用户反馈?
- 商品列表滚动区域太小,很难找到想要的商品。
- 头部的搜索广告占据了半个屏幕,挤占了实际空间。
- 在我手机这样小的屏幕上,展示区域太小了,能否把它放大点?
在电商页面中,我们需要向用户展示众多的商品、广告等信息。
然而,如何在有限的屏幕空间中更好地展示它们,是一个需要我们深入思考的问题。
由于小程序 webview 渲染框架在技术存在一定的局限性,我们需要在不同的设计之间进行抉择。
- 当广告具有较高的优先级时,我们会考虑突出广告的展示,同时减小商品列表在界面中所占比例。
- 当商品列表具有较高的优先级时,我们会考虑优先展示商品,而放弃广告的展示。
但是当广告和商品列表同样重要的情况下,要怎么办呢?
常见的一种设计方式是设计一个隐藏按钮,当用户不想看广告的时候把广告隐藏掉,隐藏之后商品列表就有更多展示空间
但是这种情况也只是针对愿意手动点击隐藏按钮的情况下,还是有一定的局限性。
那么,有没有办法做到在无形中隐藏广告呢?
说到这里,当然是可以的啦✌️
1、吸顶布局 + worklet 轻松实现
在常见的电商小程序首页,通常是顶部展示类目、接着展示商品详情,商品详情顶部也有热门等等的分类。
当页面滚动的时候,我们希望商品详情热门分类可以吸在顶部,便于切换。
这里我们用到了 scroll-view 的 sticky-header、sticky-section 吸顶布局容器即可轻松实现。
<scroll-view
type="custom"
scroll-y
show-scrollbar="false"
worklet:onstartstart="handleScrollStart"
worklet:onscrollupdate="handleScrollUpdate"
worklet:onscrollend="handleScrollEnd"
>
<sticky-section push-pinned-header="false">
<sticky-header>
<!-- 搜索框 -->
...
</sticky-header>
<!-- 类目展示 -->
</sticky-section>
<sticky-section push-pinned-header="false" padding="[
0,
16,
0,
16
]">
<sticky-header>
<!-- 商品详情热门分类 -->
...
</sticky-header>
<grid-view cross-axis-count="2" type="masonry">
<!-- 两列的瀑布流 -->
...
</grid-view>
</sticky-section>
</scroll-view>
当 scroll-view 滚动的时候,根据滚动位置把搜索框放到标题的位置,可以再节省一点空间
attached() {
// nav-bar 隐藏或展示
this.applyAnimatedStyle('.nav-bar', () => {
'worklet'
return {
opacity: this.navBarOpactiy.value
}
})
// 改变搜索框宽度
this.applyAnimatedStyle('.search', () => {
'worklet'
return {
width: `${this.searchBarWidth.value}%`,
}
})
},
// scroll-view 监听函数
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.searchBarWidth.value = lerp(100, 70, EasingFn(progress))
this.navBarOpactiy.value = lerp(1, 0, progress)
},
2、手势 + worklet 操作更灵活
小程序新渲染框架支持了手势系统,手势在这里可以发挥大作用~
我们可以使用手势协商让小程序页面中的广告、商品等无缝切换和更好的展示
// .wxml
<pan-gesture-handler
tag="pan"
simultaneousHandlers="[
"scroll-view"
]"
shouldResponseOnMove="shouldPanResponse"
onGestureEvent="handlePan"
>
<view class="page">
<vertical-drag-gesture-handler
tag="scroll-view"
native-view="scroll-view"
simultaneousHandlers="[
"pan"
]"
shouldResponseOnMove="shouldScrollViewResponse"
>
<scroll-view
class="product-list"
type="custom"
scroll-y
show-scrollbar="false"
adjustDecelerationVelocity="adjustDeceleration"
bindscroll="handleScroll"
>
...
</scroll-view>
</vertical-drag-gesture-handler>
</view>
</pan-gesture-handler>
// .js
handlePan(e) {
'worklet'
...
if (e.state === GestureState.ACTIVE) {
if (this._interactionState.value === InteractionState.UNFOLD) {
// 展开状态下,往上滑才折叠起来
if (e.absoluteY - this._startY.value < 0) {
this._interactionState.value = InteractionState.ANIMATING
this._translY.value = timing(0.0, { duration: 250 }, () => {
'worklet'
this._interactionState.value = InteractionState.RESET
})
}
} else {
// 其它情况,跟随手指滑动
this._translY.value = e.absoluteY - this._startY.value
}
}
// 其他状态下的处理
...
},
加入手势之后,除了可以隐藏广告,我们还可以将一些头部信息隐藏
在用户查看商品列表时,隐藏大部分无用信息,将商品列表展示区域最大化
// 最外层 .page 往上挪
this.applyAnimatedStyle('.page', () => {
'worklet'
const translY = clamp(this._translY.value, -this._tabsTop.value, 0)
return {
transform: `translateY(${translY}px)`
}
})
// 改变 .navigation-bar 背景色
this.applyAnimatedStyle('.navigation-bar', () => {
'worklet'
const translY = clamp(this._translY.value, -this._tabsTop.value, 0)
const opacity = translY / -this._tabsTop.value
return {
backgroundColor: `rgba(255, 255, 255, ${opacity})`
}
})
// 输入框:改变宽度并且展示
this.applyAnimatedStyle('.search-input', () => {
'worklet'
const translY = clamp(this._translY.value, -this._tabsTop.value, 0)
const percentage = translY / -this._tabsTop.value
return {
width: `${percentage * 60 + 40}%`,
opacity: percentage,
}
})
除此之外,我们这里可以利用手势来展示商家的一些信息
当在商品列表往下拉到顶部时,触发整个列表下拉展示出商家信息
再往上滑动则商品列表重新展示~
// 商品详情往下拉
this.applyAnimatedStyle('.main', () => {
'worklet'
const translY = clamp(this._translY.value, 0, Number.MAX_VALUE)
console.log(222, translY)
return {
transform: `translateY(${translY}px)`
}
})
// 简单的 header 渐隐
// 商品详情展示时,仅显示简单的 header:学堂名称和几个标签
this.applyAnimatedStyle('.header-shop-info-simple', () => {
'worklet'
const min = 50
const max = 100
const translY = clamp(this._translY.value, min, max) - min
return {
opacity: 1 - (translY / (max - min))
}
})
// 复杂的 header 渐显
// 商品详情下拉,显示复杂 header:展示热门活动、公告等等信息
this.applyAnimatedStyle('.header-shop-info-detail', () => {
'worklet'
const min = 100
const max = 150
const translY = clamp(this._translY.value, min, max) - min
return {
opacity: translY / (max - min)
}
})
加入手势动画之后,我们的页面展示对比之前有了以下的优势:
- 更加自然:更符合用户操作习惯,用户自然滚动屏幕时不会感到突兀
- 更节省空间:滚动隐藏更为灵活、省空间,使页面更清爽
- 更高效的展示:可以将要展示的内容更好的展示,无需做取舍
借助手势动画,我们可以优化小程序界面展示、提升用户体验,从而获得更高的商业价值。
如果你也想更好的留住用户,mark 下这个 源码 [ 瀑布流页面 / 分类页面 ] 直接接到到你的小程序吧~