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

相关推荐
mon_star°1 小时前
搭建基于火灾风险预测与防范的消防安全科普小程序
安全·微信小程序·小程序·微信公众平台
换日线°4 小时前
CSS常遇到自适应高度动画、带三角气泡阴影一行样式解决
css·微信小程序
yuanmenglxb20047 小时前
微信小程序核心技术栈
前端·javascript·vue.js·笔记·微信小程序·小程序
编程毕设8 小时前
【含文档+PPT+源码】基于微信小程序连锁药店商城
微信小程序·小程序
幽络源小助理8 小时前
微信小程序鲜花销售系统设计与实现
微信小程序·小程序
换日线°10 小时前
CSS简单实用的加载动画、骨架屏有效果图
css·微信小程序
10年前端老司机10 小时前
微信小程序wxs
前端·javascript·微信小程序
努力成为包租婆20 小时前
微信小程序 van-dropdown-menu
微信·微信小程序·小程序
thinkQuadratic1 天前
微信小程序动态设置高度,添加动画等常用操作
微信小程序·小程序
幽络源小助理1 天前
微信小程序文章管理系统开发实现
java·微信小程序·springboot