开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情
前言
Home 页面涉及到的内容较多,我将会拆分成三篇文章来介绍其中的技术点,本篇是第一篇,介绍页面顶部搜索框与页面滚动时切换顶部颜色的实现。
本篇文章对应代码分支:home-header
技术点
自定义头部
监听页面滚动
setData 优化
一、效果介绍
由于首页截图太长,影响浏览,在此只放出图片链接,可点击查看: 点击查看首页截图
本篇文章主要介绍以下两部分:
- 自定义头部与搜索框的位置处理
- 滚动时顶部颜色变更,效果如下:
- 变更前:
- 变更后
二、页面结构
首页以及之后的所有页面,只要是功能可拆分的,都会拆分为组件,如果是页面级不会被其它页面共用的,则放在当前页面下的 components
目录下,如果能被共用的,则放到全局的 components
目录下,结构如下:
└── pages
└── home // 首页文件夹
├── components // 首页相关组件
│ ├── home-header // 自定义头部组件
│ ├── home-swiper // swiper 组件
│ └── home-menu // 导航菜单组件
├── index.js
├── index.json
├── index.wxml
└── index.scss
这里有个创建文件的小技巧,无论是页面还是组件,都可以在开发者工具的文件管理中右键输入文件名,回车即可创建好相关文件,如下图所示。
三、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
是如何计算出来的:
胶囊的宽高我们也需要记录下,搜索框会使用到:
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. 效果预览
当页面滚动到一定距离时,头部将变成固定的主题色(通过滚动可以做一些顶部导航栏变化的特效,后面的影视详情页会有涉及)。
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
的使用与变化背景的实现。
暂无评论内容