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

相关推荐
罗狮粉 993 小时前
docker部署微信小程序自动构建发布和更新
docker·微信小程序·notepad++
Kika写代码16 小时前
【微信小程序】页面跳转基础 | 我的咖啡店-综合实训
服务器·微信小程序·小程序
源码哥_博纳软云17 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
YUJIAN。18 小时前
使用uniapp开发微信小程序-框架搭建
微信小程序·小程序·uni-app
V+zmm101341 天前
基于微信小程序的乡村政务服务系统springboot+论文源码调试讲解
java·微信小程序·小程序·毕业设计·ssm
还这么多错误?!1 天前
uniapp微信小程序,使用fastadmin完成一个一键获取微信手机号的功能
微信小程序·小程序·uni-app
_院长大人_1 天前
微信小程序用户信息解密 AES/CBC/NoPadding 解密失败问题
微信小程序·小程序
407指导员1 天前
uniapp 微信小程序 页面部分截图实现
微信小程序·小程序·uni-app
三木吧1 天前
开发微信小程序的过程与心得
人工智能·微信小程序·小程序
Kika写代码1 天前
【微信小程序】3|首页搜索框 | 我的咖啡店-综合实训
微信小程序·小程序