Weapp影视评分项目开发(08):Home 页的实现 (01 自定义顶部导航栏与滚动变色的实现)

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情

前言

Home 页面涉及到的内容较多,我将会拆分成三篇文章来介绍其中的技术点,本篇是第一篇,介绍页面顶部搜索框与页面滚动时切换顶部颜色的实现。

本篇文章对应代码分支:home-header

技术点

自定义头部 监听页面滚动 setData 优化

一、效果介绍

由于首页截图太长,影响浏览,在此只放出图片链接,可点击查看: 点击查看首页截图

本篇文章主要介绍以下两部分:

  1. 自定义头部与搜索框的位置处理
  2. 滚动时顶部颜色变更,效果如下:
  • 变更前:
    home-header-1.jpg
  • 变更后
    home-header-2.jpg

二、页面结构

首页以及之后的所有页面,只要是功能可拆分的,都会拆分为组件,如果是页面级不会被其它页面共用的,则放在当前页面下的 components 目录下,如果能被共用的,则放到全局的 components 目录下,结构如下:

└── pages
    └── home                   // 首页文件夹
        ├── components         // 首页相关组件
        │   ├── home-header    // 自定义头部组件
        │   ├── home-swiper    // swiper 组件
        │   └── home-menu      // 导航菜单组件
        ├── index.js
        ├── index.json
        ├── index.wxml
        └── index.scss

这里有个创建文件的小技巧,无论是页面还是组件,都可以在开发者工具的文件管理中右键输入文件名,回车即可创建好相关文件,如下图所示。

component.gif

三、home-header 组件

1. 开启自定义头部

首先,我们需要去掉首页的顶部导航栏,微信小程序提供了页面级的配置,我们打开之前创建的 home 文件夹下的 index.json 文件,增加如下配置项:

"navigationStyle": "custom"

2. 自定义头部导航栏的实现

现在手机存在刘海、挖孔等异形屏,导致顶部状态栏的高度并不一致,所以在实现自定义导航栏之前,我们先了解下如何获取状态栏与标题栏的高度。

1) 获取状态栏高度

微信小程序提供了 wx.getSystemInfo() 或者新的 wx.getWindowInfo() 方法用于获取设备或者屏幕信息,其中就有状态栏的高度(statusBarHeight)。

const windowInfo = wx.getWindowInfo();
const statusBarH = windowInfo.statusBarHeight; // 状态栏高度
2) 获取标题栏高度

标题栏高度无法直接获取,小程序提供了一个获取右上角胶囊按钮位置信息的方法 getMenuButtonBoundingClientRect() ,我们可以通过这个数据换算出标题栏的高度。

const capsule = wx.getMenuButtonBoundingClientRect(); // 获取胶囊位置数据
const titleBarH = capsule.top + capsule.bottom - statusBarH * 2; // 标题栏高度

当然,titleBarH 也可以这样计算:

// 胶囊距离状态栏的高度x2 + 胶囊的高度
const titleBarH = (capsule.top - statusBarH) * 2 + capsule.height;

通过下面这个图片,可以更直观的了解 titleBarH 是如何计算出来的:

header.jpg

胶囊的宽高我们也需要记录下,搜索框会使用到:

const capsuleH = capsule.height; // 胶囊高度,用于搜索框
const capsuleW = capsule.width; // 胶囊宽度,用于搜索框
3) 方法的封装

因为项目中有多处使用到状态栏与标题栏的高度信息,我们可以将这些数据放到 app.globalData 对象中。
首先我们将如何获取导航栏信息的代码封装为一个方法放在 utils 下,命名为 systemInfo.js,并将数据作为一个对象导出。

// utils/systemInfo.js
export default () => {
  const windowInfo = wx.getWindowInfo();
  const statusBarH = windowInfo.statusBarHeight; // 状态栏高度
  const capsule = wx.getMenuButtonBoundingClientRect();
  const titleBarH = capsule.top + capsule.bottom - statusBarH * 2; // 标题栏高度
  const capsuleH = capsule.height; // 胶囊高度,用于搜索框
  const capsuleW = capsule.width; // 胶囊宽度,用于搜索框

  return {
    statusBarH,
    titleBarH,
    capsuleH,
    capsuleW
  }
}
4) 注册到全局

之后在 app.js 中导入该方法,并在 onLaunch() 生命周期中调用后,将数据添加到 globalData 下,我们可以使用 ES6 语法 Object.assign 进行合并,代码如下:

// app.js
import systemInfo from "./utils/systemInfo";

App({
  globalData: {}, // 存放一些全局使用的数据
  // 小程序初始化完成时触发,全局只触发一次
  onLaunch() {
    this.globalData = Object.assign(this.globalData, systemInfo()); // 数据合并
  },
})
5) 数据的使用

home-header/index.js 使用时只需要从 app.globalData 中获取:

const app = getApp();
// 将 header 信息放到 data 中
data: {
  statusBarH: app.globalData.statusBarH,
  titleBarH: app.globalData.titleBarH,
  searchBarH: app.globalData.capsuleH,
  capsuleW: app.globalData.capsuleW,
}

以上即为 home-header 实现的主要代码,搜索框高度和胶囊高度一致,宽度减去胶囊宽度即可,详情可以查看源码,不做赘述。

四、监听页面滚动并改变样式

微信小程序无法像 web 那样在组件中注册页面滚动监听事件,但其页面级提供了 onPageScroll 事件,能够获取到滚动的数值,我们可以将此值通过 properties 传递给子组件。

优化点:通过 properties 传递页面滚动高度变化,会频繁触发 setData ,影响性能,而这里的自定义 home-header 中无需知道具体高度的变化,所以我们只需要给 home-header 组件传递个是否需要变换头部颜色的状态值即可,而计算部分则放在 onPageScroll 中。

1. 效果预览

当页面滚动到一定距离时,头部将变成固定的主题色(通过滚动可以做一些顶部导航栏变化的特效,后面的影视详情页会有涉及)。

scroll.gif

2. 滚动事件的使用

微信小程序提供了页面级的滚动事件 onPageScroll ,由于该事件无法在组件中注册,我们只能通过传值的方式通知组件。

// home/index.js
onPageScroll({ scrollTop }) {  // 能用 ES6语法的地方尽量使用,此处使用了对象解构
  this.setData({
    scrollTop   // 注意此处会频繁触发 
  })
}

3. setData 的优化

// home/index.js
onPageScroll({ scrollTop }) {  // 能用 ES6语法的地方尽量使用,此处使用了对象解构
  const threshold = 100; // 滚动变化的阈值,超出则顶部显示为主题色
  // 此处使用 isTop 字段作为当前是否在顶部的状态值
  // 大于阈值且状态为 true 时,才需要将 isTop 置为 false
  if (scrollTop > threshold && this.data.isTop) {
    this.setData({
      isTop: false
    })
  // 未到达阈值且状态值为 false 时,才需要将 isTop 置为 true,
  } else if (scrollTop <= threshold && !this.data.isTop) {
    this.setData({
      isTop: true
    })
  }
}

注意:以上代码对 setData 做了优化,只有当需要状态变更时,才会触发 setData ,不会造成频繁触发。

最后

本篇文章主要介绍了自定义头部的实现,onPageScroll 方法的使用以及如何优化避免频繁触发,日常使用的一些 App 中经常会看到这类的效果,有些还会实现元素状态改变的特效,但万变离其中,都是通过监听页面滚动距离实现的。
感谢阅读,下一篇我将介绍 swiper 的使用与变化背景的实现。

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容