# 混入
# 介绍
微信小程序的 behaviors
(opens new window) ,与 vue
的 mixins
相似,为了与 vue
保持一致,文件命名为 mixins
。
# 目录结构
└─ mixins # 混入
└─ getInfiniteData.js # 无限滚动加载
# getInfiniteData.js
无限滚动加载
本项目中存在大量的列表类页面,如 正在热映、Top 100、 影评列表 等,这些页面存着共性方法是 滚动触底加载更多 与 下拉刷新方法;所以将这些页面的共性部分抽离出来共用,可以极大的减少重复代码。
# 小程序组件的 behaviors
方法:
- 虽然小程序官方文档中
behaviors
只可在组件中使用,但实际使用发现在 页面级也是有效的。 - 由于组件与页面都有
ready
方法,所以behaviors
中会在该生命周期中调用页面/组件中的接口请求。
// 引入计算属性
const computedBehavior = require('miniprogram-computed').behavior
module.exports = Behavior({
behaviors: [computedBehavior],
// 初始化一些数据
data: {
id: null, // 详情页面的资源ID,可选值
loading: false, // 页面接口请求loading
noData: false, // 无数据
noMoreData: false, // 无更多数据
form: {}, // 查询条件
list: [], // 接口返回 data 中的列表数据
total: 0, // 列表数据总条数
page: 1, // 当前页码
per_page: 20, // 每页返回数量
_isError: false, // 接口报错
},
computed: {
// 是否显示加载骨架屏动画
isShowSkeleton(data) {
// 只有接口请求中并且当前为第一页时才显示骨架屏,否则显示页底的 <m-loadmore /> 组件
return data.loading && data.page === 1;
},
},
ready() {
// 调用加载方法
this.loadMore();
},
methods: {
// 下拉刷新时重置data数据
resetData() {
// 已在下拉加载状态是禁止接口请求,防止重复请求导致数据重复
if (this.data.loading) return;
this.setData({
loading: false,
page: 1,
list: [],
total: 0,
noData: false,
noMoreData: false,
_isError: false,
})
this.loadMore();
},
/**
* @desc 分页获取更多数据
* @param Function fn 接口请求方法,在 api 文件夹在定义的方法
* @param Object ...args 接口请求参数,可以未多个,使用...运算符对参数进行分解
* @return 无返回结果,相关数据已挂载在当前组件实例上
*/
async getData(fn, ...args) {
// 接口请求失败时阻止继续请求
if (this.data._isError) return;
// 设置无更多数据时标志,当前为第一页且无数据时,可以再次触发请求
if (this.noMoreData && this.page === 1 && this.list.length === 0) {
this.noMoreData = false;
}
// 接口请求中或者无更多数据时,拦截请求
if (this.data.loading || this.data.noMoreData) return;
// 接口请求标志位
this.setData({ loading: true })
// 请求参数
let params = {
page: this.data..page,
per_page: this.data.per_page,
...this.data.form
};
/**
* @desc 接口请求
* @param ...args 多个请求参数,需要与 api 接口定义一致
* @param params 请求query中携带参数
* @return code 状态码 200 为成功
* @return data 数据列表
* @return total 数据总条数
*/
const { code, data, total } = await fn(...args, params);
// 接口请求结束时关闭下拉状态(刷拉刷新时有效)
wx.stopPullDownRefresh();
if (code === 200) {
let noData = false;
// 是否无数据,当前为第一页且返回数据为空
if (this.data.page === 1 && data.length === 0) {
noData = true;
} else {
noData = false;
}
this.data._isError = false;
// 返回数据条数小于设置的每页请求条数时,则没有更多数据了
if (data.length < this.data.per_page) {
this.setData({
noMoreData: true
})
}
// 返回的数据追加到原有列表中
this.data.list.push(...data)
this.setData({
noData,
list: this.data.list,
page: ++this.data.page, // 返回成功后当前页码+1
total: total || 0,
})
} else {
// 接口失败时设置失败标志位为 true,阻止滚动继续发起请求
this.data._isError = true;
}
// 渲染完成后隐藏加载动画
wx.nextTick(() => {
this.setData({
loading: false
})
});
},
},
})
# 使用示例
<view class="list">
<!-- 列表内容 -->
<list-item
wx:for="{{ list }}"
wx:key="id"
item="{{ item }}"
/>
</view>
<m-loadmore loading="{{loading}}" />
Page({
// 注入混入内容,混入方法已在 app.js 中挂载在 wx 对象上
behaviors: [wx.getInfiniteData],
// 页面滚动触底会调用 loadMore 方法,getData 方法在上面的 mixins 里面定义了
loadMore() {
this.getData(request, ...params);
},
// 触底方法请看下面 Page 扩展
})
# Page 构造函数的扩展
该方法主要扩展了下拉刷新与滚动触底两个方法,如有其它需求可以自主扩展。
onPullDownRefresh
下拉刷新方法,需要在页面的app.json
文件中开启下拉刷新配置。
{
"enablePullDownRefresh": true
}
onReachBottom
页面.json
文件中onReachBottomDistance: 50
配置为默认值,如触底高度无需改变,可不写。
以下为 Page
扩展代码
const expandPage = () => {
const originalPage = Page;
Page = function (config) {
// 获取 Page 下拉刷新与触底方法
const { onPullDownRefresh, onReachBottom } = config;
// 下拉刷新
config.onPullDownRefresh = function () {
// 页面存在下拉刷新方法时,则使用页面中定义的方法
if (typeof onPullDownRefresh === 'function') {
onPullDownRefresh.call(this);
} else {
// 页面存在 resetData 与 loadMore 方法时才会调用该方法
if (typeof this.resetData === 'function' && typeof this.loadMore === 'function') {
this.resetData();
}
}
}
// 重写触底方法
config.onReachBottom = function () {
// 页面存在触底方法时,则使用页面中定义的方法
if (typeof onReachBottom === 'function') {
onReachBottom.call(this);
} else {
// 页面存在 loadMore 方法,则触底时调用该方法
if (typeof this.loadMore === 'function') {
this.loadMore();
}
}
}
// 返回重写后的 Page 方法
return originalPage(config)
}
}
App({
async onLaunch() {
// 调用该方法将全局 Page 重写
expandPage()
}
})