微信小程序自定義組件 Component - 初始化頁(yè)面

一般情況下大多數(shù)頁(yè)面在加載時(shí)都需要進(jìn)行一些網(wǎng)絡(luò)檢查、基礎(chǔ)配置數(shù)據(jù)的加載,而如果每個(gè)頁(yè)面都寫一遍顯然是特別愚蠢的做法,同樣是一件特別苦惱的事情。
所以,懶人自有懶辦法,提取通用 page init component,組合達(dá)到當(dāng)前小程序想要實(shí)現(xiàn)的效果。

Ta 里面有什么?

  • 頁(yè)面初始化時(shí)的網(wǎng)絡(luò)監(jiān)察
  • 頁(yè)面初始化時(shí)的必要數(shù)據(jù)加載
  • 頁(yè)面初始化時(shí)的 Loading 交互
  • 頁(yè)面初始化失敗時(shí)的提醒

實(shí)現(xiàn)結(jié)果

# 頁(yè)面初始化

# 由于網(wǎng)絡(luò)原因頁(yè)面初始化失敗

實(shí)現(xiàn)

在嘗試實(shí)現(xiàn)前,先將實(shí)現(xiàn)步驟梳理和歸納一下,找到其中的規(guī)律便于在接下來(lái)開(kāi)發(fā)中編碼并且對(duì)于維護(hù)也能順理成章。

  1. 一個(gè) Loading 界面
  2. 一個(gè)能夠接收入?yún)⒌腻e(cuò)誤提醒界面
  3. 實(shí)現(xiàn)網(wǎng)絡(luò)檢查函數(shù)
  4. 核心配置數(shù)據(jù)請(qǐng)求
  5. 回調(diào)通知父級(jí)函數(shù)

達(dá)到以上條件,基本上就成功了一半,初始已具有一定模型。

component 的實(shí)現(xiàn)

init.wxml 基礎(chǔ)結(jié)構(gòu)

<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>回到主頁(yè)</button>
                    <button>聯(lián)系客服</button>
                </view>
            </view>

        </view>
    </view>
</view>

以上的代碼邏輯很簡(jiǎn)單
1.loadingerrStatus 均為 false 時(shí),顯示插槽內(nèi)的內(nèi)容, slot page 插槽,就是實(shí)際 init 完成后需要顯示的內(nèi)容

  1. loadingerrStatus 任意為 true 時(shí)顯示提示,提示 Loading 狀態(tài)或異常狀態(tài)
  2. errTitle & errContent 則是異常時(shí)提示的內(nèi)容

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: '數(shù)據(jù)異常',
        errContent: '可能發(fā)生了未知錯(cuò)誤,請(qǐng)重試',
    },
    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('賬戶異常', '同步賬戶時(shí)出現(xiàn)異常,請(qǐng)重新嘗試')
                        reject(err)
                    }
                )
            })
        },
        network: function() {
            return new Promise((resolve, reject) => {
                wx.getNetworkType({
                    success: res => {
                        if (res.networkType != 'none') {
                            resolve(true)
                        } else {
                            this.showError('網(wǎng)絡(luò)異常', '請(qǐng)檢查您的網(wǎng)絡(luò)連接')                            
                            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中定義組件的對(duì)外屬性,便于父級(jí)頁(yè)面在引用時(shí)進(jìn)行配置,在我自己小程序中,同步用戶數(shù)據(jù)是我的核心配置函數(shù),我需要在所有頁(yè)都同步用戶數(shù)據(jù)且配置不相同,所有有此定義,具體細(xì)節(jié)不表了。

  1. resyncUsertrue,強(qiáng)制同步;false,引用變量緩存
  2. loopInit:表示是否需要循環(huán)初始化,在 component 無(wú)法監(jiān)聽(tīng) 父級(jí)的 onLoad 事件,所以父級(jí)每次 onShow 時(shí)都會(huì)被初始化,該參數(shù)則決定是否要將其阻斷。ture,每次 onShow 都初始化;false,僅初始化一次
  3. autoHide 表示初始化完成后是否要自動(dòng)隱藏 init。true,初始化完成后自動(dòng)隱藏;false,初始化后的隱藏決定權(quán)交給父級(jí)

.json 配置組件

"usingComponents": {
    "INIT": "/pages/_copts/init/main"
}

.wxml 中的使用

<INIT id="init"
loopInit="{{false}}" autoHide="{{false}}"
bind:callback="init">
    <view slot="page">
        <!-- 你的代碼  -->       
    </view>
</INIT>

在具體使用該 init 的父級(jí)頁(yè)中配置 json 和引用 init 組件并對(duì)其 loopInit autoHide callback 進(jìn)行配置。
如果想直接使用,也可以不用配置交給默認(rèn)值決定。

額外事項(xiàng)

在組件的 init.js 中我們定義多個(gè)方法,可以使用在父級(jí)節(jié)點(diǎn)使用 this.selectComponent 獲取組件示例后調(diào)用

  1. this.selectComponent('#init').hide()
  2. this.selectComponent('#init').showError('title','content')
    這里不太推薦直接訪問(wèn)和修改組件的屬性,我們僅提供方法調(diào)用,交給組件自身去修改屬性避免錯(cuò)亂。

番外

其實(shí)對(duì)于初始化的辦法很多種,我這里是的辦法是根據(jù)自身的小程序特性和需要而確定,具體的源碼估計(jì)對(duì)看官意義也不甚大,我就不獻(xiàn)丑了。文章的意義更多的還是拋磚引玉與記錄自身在寫代碼過(guò)程中的感想體悟。如果你有想法或打臉請(qǐng)隨時(shí)留言。

以上,
玩的開(kāi)心!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容