美文网首页微信小程序
微信小程序自定义组件 Component - 初始化页面

微信小程序自定义组件 Component - 初始化页面

作者: 我是大阳哥啊 | 来源:发表于2020-03-07 03:11 被阅读0次

    一般情况下大多数页面在加载时都需要进行一些网络检查、基础配置数据的加载,而如果每个页面都写一遍显然是特别愚蠢的做法,同样是一件特别苦恼的事情。
    所以,懒人自有懒办法,提取通用 page init component,组合达到当前小程序想要实现的效果。

    Ta 里面有什么?

    • 页面初始化时的网络监察
    • 页面初始化时的必要数据加载
    • 页面初始化时的 Loading 交互
    • 页面初始化失败时的提醒

    实现结果

    # 页面初始化
    # 由于网络原因页面初始化失败

    实现

    在尝试实现前,先将实现步骤梳理和归纳一下,找到其中的规律便于在接下来开发中编码并且对于维护也能顺理成章。

    1. 一个 Loading 界面
    2. 一个能够接收入参的错误提醒界面
    3. 实现网络检查函数
    4. 核心配置数据请求
    5. 回调通知父级函数

    达到以上条件,基本上就成功了一半,初始已具有一定模型。

    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.loadingerrStatus 均为 false 时,显示插槽内的内容, slot page 插槽,就是实际 init 完成后需要显示的内容

    1. loadingerrStatus 任意为 true 时显示提示,提示 Loading 状态或异常状态
    2. 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中定义组件的对外属性,便于父级页面在引用时进行配置,在我自己小程序中,同步用户数据是我的核心配置函数,我需要在所有页都同步用户数据且配置不相同,所有有此定义,具体细节不表了。

    1. resyncUsertrue,强制同步;false,引用变量缓存
    2. loopInit:表示是否需要循环初始化,在 component 无法监听 父级的 onLoad 事件,所以父级每次 onShow 时都会被初始化,该参数则决定是否要将其阻断。ture,每次 onShow 都初始化;false,仅初始化一次
    3. 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 获取组件示例后调用

    1. this.selectComponent('#init').hide()
    2. this.selectComponent('#init').showError('title','content')
      这里不太推荐直接访问和修改组件的属性,我们仅提供方法调用,交给组件自身去修改属性避免错乱。

    番外

    其实对于初始化的办法很多种,我这里是的办法是根据自身的小程序特性和需要而确定,具体的源码估计对看官意义也不甚大,我就不献丑了。文章的意义更多的还是抛砖引玉与记录自身在写代码过程中的感想体悟。如果你有想法或打脸请随时留言。

    以上,
    玩的开心!

    相关文章

      网友评论

        本文标题:微信小程序自定义组件 Component - 初始化页面

        本文链接:https://www.haomeiwen.com/subject/cquxdhtx.html