微信开发者

页面布局新玩法,用户留存更给力

随着小程序的应用场景越来越丰富,小程序提供更多元的功能,这也意味着有限的页面需要承载更多的内容。以常见的页面布局为例,一屏不仅需要提供多样的功能选项,完成业务链路;还需要占据较大版面曝光近期重点内容,场景化完成宣传。

Image

页面布局示例

对于业务决策者而言,这两个展示渠道同样重要,但如何平衡二者的展示逻辑并不简单。

  • 关注功能选项,则难以搭建曝光位,尤其在多层级功能选项下,无法实现导航栏位置固定

  • 关注宣传曝光,则功能位范围变小,特别影响小屏幕手机用户的使用体验

Image

针对这种页面信息量丰富的情况,应用 小程序渲染框架 的核心能力即可快速实现页面合理布局,保证良好的交互体验与功能需求,吸引用户继续使用,业务流程更丝滑。

无缝切换功能位 & 曝光位

平衡功能位与曝光位的理想状态是:用户能够看到曝光内容,保证成功推广;同时如果用户对曝光内容不感兴趣,曝光内容随着功能位出现而无缝切换,保证良好的交互体验。

Image

实现这种效果仅需应用 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>
// .jshandlePan(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,  }})

除此以外,针对某些必要但应用频率较少的信息,例如外卖小程序显示商家资质等信息,应用 worklet 动画和手势操作可以实现下拉显示更多内容,手势操作更丝滑,减少默认点按操作的滞后感。

Image

👉 点击查看代码

// 商品详情往下拉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)  }})

轻松实现吸顶布局

在上述页面下拉过程中,我们可以看到功能位到达页面顶部时,顶部导航栏自动吸顶,进一步扩大功能选项区域的可视范围。

Image

吸顶布局 VS 无吸顶布局

除了导航栏等框架工具,搜索框等常用功能同样可以通过吸顶布局便利用户的使用体验。例如下述动图的通过双重吸顶搜索框和导航栏,方便用户在下滑至后方内容,无需回到顶部进行搜索或分类操作,交互体验更丝滑。

Image

实现以上吸顶能力仅需应用 sticky-header、sticky-section 2 个组件;同时通过巧妙调整搜索框吸顶位置至小程序开关胶囊所在位置,进一步节约页面空间。

👉 点击查看代码

<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>
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)},

通过对 小程序渲染框架 的灵活应用,小程序既能轻松实现更贴近原生的交互效果,提升开发效率;又能保证流畅、丝滑的用户体验,高效留存用户,赋能业务发展。

小程序渲染框架 持续支持开发者的渲染需求,实现在多个终端稳定、贴近原生的交互体验,赋能业务发展。欢迎各位开发者关注 小程序渲染框架更新日志 了解更多最新动态或者访问 小程序示例 发现最佳实践。