一般情况下大多数页面在加载时都需要进行一些网络检查、基础配置数据的加载,而如果每个页面都写一遍显然是特别愚蠢的做法,同样是一件特别苦恼的事情。
所以,懒人自有懒办法,提取通用 page init component,组合达到当前小程序想要实现的效果。
Ta 里面有什么?
- 页面初始化时的网络监察
- 页面初始化时的必要数据加载
- 页面初始化时的 Loading 交互
- 页面初始化失败时的提醒
实现结果
实现
在尝试实现前,先将实现步骤梳理和归纳一下,找到其中的规律便于在接下来开发中编码并且对于维护也能顺理成章。
- 一个 Loading 界面
- 一个能够接收入参的错误提醒界面
- 实现网络检查函数
- 核心配置数据请求
- 回调通知父级函数
达到以上条件,基本上就成功了一半,初始已具有一定模型。
component 的实现
init.wxml 基础结构
<view>
<view wx:if="{{!loading && !errStatus}}">
<slot name="page"></slot>
</view>
<view class="{{ (loading || errStatus) ? 'show':'' }}">
<view>
<!-- Loading -->
<view wx:if="{{loading}}"><text>Loading</text></view>
<!-- Error -->
<view wx:if="{{errStatus}}">
<view>
<view>{{errTitle}}</view>
<view>{{errContent}}</view>
</view>
<view>
<button>再次尝试</button>
<button>回到主页</button>
<button>联系客服</button>
</view>
</view>
</view>
</view>
</view>
以上的代码逻辑很简单
1.loading
与 errStatus
均为 false
时,显示插槽内的内容, slot page
插槽,就是实际 init 完成后需要显示的内容
-
loading
或errStatus
任意为true
时显示提示,提示 Loading 状态或异常状态 -
errTitle
&errContent
则是异常时提示的内容
init.js
Component({
options: {
addGlobalClass: true,
multipleSlots: true
},
properties: {
resyncUser: {
type: Boolean,
value: false
},
loopInit: {
type: Boolean,
value: false
},
autoHide: {
type: Boolean,
value: true
}
},
data: {
loading: true,
errStatus: false,
errTitle: '数据异常',
errContent: '可能发生了未知错误,请重试',
},
pageLifetimes: {
show: function() {
if (!this._showLoop || this.data.loopInit) {
this.init().then(
() => {
this._showLoop = true
}
)
}
}
},
observers: {
'loading': function (loading) {
if (loading) {
this.setData({
errStatus: false
})
}
},
'errStatus': function (errStatus) {
if (errStatus) {
this.setData({
loading: false
})
}
}
},
methods: {
init: function(){
return new Promise((resolve, reject) => {
this.showLoading()
this.network()
.then(
() => {
return this.user()
}
)
.then(
user => {
if (this.data.autoHide){
this.hide()
}
this.triggerEvent('callback', {
user: user,
userJSON: user.toJSON()
})
resolve()
}
)
.catch(
err => {
reject()
}
)
})
},
user: function() {
return new Promise((resolve, reject) => {
getApp().user.get(this.data.sync).then(
user => {
resolve(user)
},
err => {
this.showError('账户异常', '同步账户时出现异常,请重新尝试')
reject(err)
}
)
})
},
network: function() {
return new Promise((resolve, reject) => {
wx.getNetworkType({
success: res => {
if (res.networkType != 'none') {
resolve(true)
} else {
this.showError('网络异常', '请检查您的网络连接')
reject(false)
}
},
})
})
},
hide: function(){
this.setData({
loading: false,
errStatus: false
})
},
showLoading: function() {
this.setData({
loading: true
})
},
showError: function(_title, _content) {
this.setData({
errStatus: true,
errTitle: _title,
errContent: _content
})
}
}
})
在 properties
中定义组件的对外属性,便于父级页面在引用时进行配置,在我自己小程序中,同步用户数据是我的核心配置函数,我需要在所有页都同步用户数据且配置不相同,所有有此定义,具体细节不表了。
-
resyncUser
:true
,强制同步;false
,引用变量缓存 -
loopInit
:表示是否需要循环初始化,在component
无法监听 父级的onLoad
事件,所以父级每次onShow
时都会被初始化,该参数则决定是否要将其阻断。ture
,每次onShow
都初始化;false
,仅初始化一次 -
autoHide
表示初始化完成后是否要自动隐藏 init。true
,初始化完成后自动隐藏;false
,初始化后的隐藏决定权交给父级
.json 配置组件
"usingComponents": {
"INIT": "/pages/_copts/init/main"
}
.wxml 中的使用
<INIT id="init"
loopInit="{{false}}" autoHide="{{false}}"
bind:callback="init">
<view slot="page">
<!-- 你的代码 -->
</view>
</INIT>
在具体使用该 init 的父级页中配置 json 和引用 init 组件并对其 loopInit
autoHide
callback
进行配置。
如果想直接使用,也可以不用配置交给默认值决定。
额外事项
在组件的 init.js
中我们定义多个方法,可以使用在父级节点使用 this.selectComponent
获取组件示例后调用
this.selectComponent('#init').hide()
-
this.selectComponent('#init').showError('title','content')
这里不太推荐直接访问和修改组件的属性,我们仅提供方法调用,交给组件自身去修改属性避免错乱。
番外
其实对于初始化的办法很多种,我这里是的办法是根据自身的小程序特性和需要而确定,具体的源码估计对看官意义也不甚大,我就不献丑了。文章的意义更多的还是抛砖引玉与记录自身在写代码过程中的感想体悟。如果你有想法或打脸请随时留言。
以上,
玩的开心!