微信小程序自定义navigation,关于滚动动画的一点实践

自定义navigation

隐藏页面自带的navigation

自定义组件我们需要将页面的json配置navigationStyle设为custom

json 复制代码
{
  "navigationBarTitleText": "首页",
  "navigationStyle": "custom"
}

封装组件 custom-nav

计算navigation高度和胶囊按钮padding

自定义navigation需要知道两个主要信息,一个状态栏的高度,另一个是右上角微信自带的胶囊按钮,我们需要两个api查询到这两个信息,wx.getSystemInfoSyncwx.getMenuButtonBoundingClientRect

用这些信息我们可以计算出:

text 复制代码
navigation高度 = systmemInfo.statusBarHeight + 44
胶囊右边界距离屏幕右边界距离 = systemInfo.windowWidth - menuBtnRect.right
js 复制代码
const sysInfo = wx.getSystemInfoSync()
const menuBtnRect = wx.getMenuButtonBoundingClientRect()
this.navHeight = sysInfo.statusBarHeight + 44
this.menuBtnPadding = sysInfo.windowWidth - menuBtnRect.right

实现navigation title 居中和过长省略

为了防止title文本过长被胶囊按钮遮盖,思路是分为三栏,左右两栏最小宽度设为胶囊按钮的宽度,设为最小宽度是流程左侧的slot,宽度可能被实际内容撑开更长,同时右栏复制左栏,设置为隐藏

html 复制代码
<view 
  class="custom-nav" 
  style="height: {{navHeight}}px; background-color: {{navBackgroundColor}};"
>
  <view 
    class="custom-nav-content" 
    style="height: {{menuBtnRect.height}}px; margin-top: {{menuBtnRect.top}}px;"
  >
    <!-- 
      左侧有两个目的:
      1:left slot。 
      2:最小宽度样式复制menuBtn,以兼容title文字过长的省略打点演示。
    -->
    <view 
      class="custom-nav-left" 
      style="height: {{menuBtnRect.height}}px; min-width: {{menuBtnRect.width}}px; padding: 0 {{menuBtnPadding}}px; line-height: {{menuBtnRect.height}}px"
    >
    
    </view>
    <view 
      class="custom-nav-title"
      style="line-height: {{menuBtnRect.height}}px; color: {{titleColor}};"
    >
      {{title}}
    </view>
    <!-- menu btn 占位 -->
    <!-- 复制一份nav left, 不展示, 保证 title 在中间  -->
    <view 
      class="custom-nav-left" 
      style="height: {{menuBtnRect.height}}px; min-width: {{menuBtnRect.width}}px; padding: 0 {{menuBtnPadding}}px; line-height: {{menuBtnRect.height}}px; visibility: hidden;"
    >
    
    </view>
  </view>
</view>
<!-- nav 占位 -->
<view class="custom-nav-placeholder" style="height: {{navHeight}}px;"></view>

动画

这里以常见的初始透明向下滚动渐变为纯白为例,实现分为两种情况,1. 使用页面的onPageScroll,2.在scroll-view组件内使用

监听onPageScroll

首先要解决在组件内如何监听页面滚动事件,思路是使用getCurrentPages接口获取当前页面实例,修改page.onPageScroll

js 复制代码
// ....
attached: function () {
  // 如果是默认 监听 page 滚动事件
  if (!this.data.useScrollView) {
    const pages = getCurrentPages()
    const page = pages[pages.length - 1]
    this._curPage = page
    const _this = this
    if (page !== null && page !== undefined) {
      const pageScroll = page.onPageScroll
      this._pageScroll = pageScroll
      page.onPageScroll = function (e) {
        if (typeof pageScroll === 'function') {
          pageScroll.call(page, e)
        }
        _this.onScroll(e)
      }
    }
  }
},

// 组件卸载时需要取消绑定的事件
detached: () => {
  if (this.data.useScrollView) {
    if (this._pageScroll) {
      this._curPage.onPageScroll = this._pageScroll
    } else if (this._curPage) {
      this._curPage.onPageScroll = undefined
    }
  }
},

实现动画效果

js 复制代码
onScroll: function(e) {
  const scrollTop = e.scrollTop
  const navHeight = this.navHeight
  const oldNavOpacity = this.oldNavOpacity
  const navOpacity = (scrollTop / navHeight).toFixed(2)
  const oldTitleColor = this.data.titleColor

  // 滚动过快
  // 保留2位小数 相同不执行
  if (scrollTop <= navHeight && oldNavOpacity !== navOpacity) {
    this.oldNavOpacity = navOpacity
    const newData = {
      navBackgroundColor: `rgba(255, 255, 255, ${navOpacity})`
    }

    if (oldTitleColor !== '#fff') {
      newData.titleColor = '#fff'
    }
    this.setData(newData)

  } else if (scrollTop > navHeight) {
    this.oldNavOpacity = 1
    this.setData({
      navBackgroundColor: `rgba(255, 255, 255, 1)`,
      titleColor: '#333'
    })
  }
},

使用方式

html 复制代码
<view id="index-wrapper">
  <custom-nav 
    scroll-source="#index-wrapper"
    title="设置设设置设设置设设置设设置设设置设设置设设置设设置设"
  />

  <view>发射点发射点</view>
  <view style="height: 1000px;"></view>
</view>

在scroll-view内使用

使用scroll-view组件可以结合animate, 实现性能更好的动画,组件用属性use-scroll-view以区分页面滚动

js 复制代码
ready: function () {
  // scoll view animate
  if (this.data.scrollSource && this.data.useScrollView) {
    this.animate(
      '.custom-nav', 
      [{
        backgroundColor: 'rgba(255, 255, 255, 0)',
      },
      {
        backgroundColor: 'rgba(255, 255, 255, 0.5)',
      },
      {
        backgroundColor: 'rgba(255, 255, 255, 1)',
      }], 
      2000, 
      {
        scrollSource: this.data.scrollSource,
        timeRange: 2000,
        startScrollOffset: 0,
        endScrollOffset: this.navHeight,
      }
    )
  }
}

为知道何时滚动了navigation高度的距离,组件提供了一个方法

js 复制代码
onScrollView: function (e) {
  const scrollTop = e.detail.scrollTop
  const curTitleColor = this.data.titleColor
  const navHeight = this.navHeight

  if (scrollTop < navHeight) {
    if (curTitleColor !== '#fff') {
      this.setData({titleColor: '#fff'})
    }
  } else if (curTitleColor === '#fff') {
    this.setData({titleColor: '#333'})
  }
}

使用时需要在页面通过this.selectComponent获取组件实例,绑定scroll-view组件的scroll方法触发

html 复制代码
<scroll-view id="index-wrapper" scroll-y bindscroll="onScrollView">
  <custom-nav 
    scroll-source="#index-wrapper"
    title="设置设置设置设置设置设置设置设置设置设置设置设置设置设置设置"
    use-scroll-view
    id="custom-nav"
  />
</scroll-view>
js 复制代码
Page({
  onReady: function () {
    this.customNavInt = this.selectComponent('#custom-nav')
  },
  onScrollView: function (e) {
    const customNavInt = this.customNavInt
    if (customNavInt) {
      customNavInt.onScrollView(e)
    }
  }
})

最后附上源码地址

微信小程序原生自定义navigation

相关推荐
计算机-秋大田9 分钟前
基于微信小程序的平安驾校预约平台的设计与实现(源码+LW++远程调试+代码讲解等)
java·spring boot·微信小程序·小程序·vue·课程设计
DK七七4 小时前
多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码
开发语言·前端·微信小程序·小程序·php
小小码神Sundayx5 小时前
三、模板与配置(下)
笔记·微信小程序
晓风伴月7 小时前
uniapp: IOS微信小程序输入框部分被软键盘遮挡问题
微信小程序·小程序·uni-app
计算机-秋大田8 小时前
基于微信小程序的乡村研学游平台设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
小马哥编程11 小时前
【微信小程序】报修管理
微信小程序·小程序
前端(从入门到入土)13 小时前
微信小程序自定义顶部导航栏(适配各种机型)
微信小程序·小程序
放逐者-保持本心,方可放逐20 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
计算机-秋大田20 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
尚学教辅学习资料1 天前
基于微信小程序的电商平台+LW示例参考
java·微信小程序·小程序·毕业设计·springboot·电商平台