微信小程序自定义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

相关推荐
骆晨学长31 分钟前
基于springboot的智慧社区微信小程序
java·数据库·spring boot·后端·微信小程序·小程序
李宥小哥4 小时前
微信小程序07-开发进阶
微信小程序·小程序·notepad++
2401_8459375315 小时前
PHP一键约课高效健身智能健身管理系统小程序源码
微信·微信小程序·小程序·微信公众平台·微信开放平台
程序员入门进阶17 小时前
基于微信小程序的科创微应用平台设计与实现+ssm(lw+演示+源码+运行)
微信小程序·小程序
计算机源码社1 天前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题
双普拉斯1 天前
微信小程序点赞动画特效实现
nginx·微信小程序·notepad++
程序员阿龙1 天前
【2025】基于微信小程序的网上点餐系统设计与实现、基于微信小程序的智能网上点餐系统、微信小程序点餐系统设计、智能点餐系统开发、微信小程序网上点餐平台设计
微信小程序·小程序·毕业设计·订单管理·在线点餐·订单跟踪·在线支付
Angus-zoe1 天前
uniapp+vue+微信小程序实现侧边导航
vue.js·微信小程序·uni-app
开利网络2 天前
综合探索数字化转型的奥秘与前景
运维·微信小程序·自动化·产品运营·数字化营销
张人玉2 天前
微信小程序开发——比较两个数字大小
微信小程序·小程序