武装少女在线观看高清完整版免费,丝袜+亚洲区,少妇被cao高潮呻吟声,午夜伦情电午夜伦情电影,日日躁夜夜躁狠狠躁

小程序模板網(wǎng)

手把手系列,100行代碼搞定微信小程序全局狀態(tài)同步

發(fā)布時(shí)間:2018-12-14 08:54 所屬欄目:小程序開(kāi)發(fā)教程

最近接了一個(gè)小程序項(xiàng)目,對(duì)于以前只寫(xiě)過(guò)一個(gè)小工具的我而言,是時(shí)候考察一波小程序的基本功了(認(rèn)真臉)。

上手先了解了各路大神擼小程序的方式,前有基于vue語(yǔ)法的mpvue ,專(zhuān)職生成小程序;又有基于react的京東團(tuán)隊(duì)的taro 在后,一語(yǔ)多端,支持react語(yǔ)法生成小程序、H5、react-native......;還有官方wepy,仿vue語(yǔ)法,官方支持更穩(wěn)定......都芥末:ox:的嗎? 趕緊每個(gè)都學(xué)習(xí)了一下。

然鵝——

??!翻開(kāi)issue頁(yè),似乎都有幾十到上百條的open isuue未解決,同時(shí)還有一些詭異的bug夾雜其中,好怕怕。遂放棄......逃

于是手?jǐn)]原生框架,于是遇到了原生框架中一個(gè)最大的問(wèn)題,全局狀態(tài)同步管理 /(ㄒoㄒ)/~~。

小程序框架提供了許多開(kāi)箱即用的組件,大大提高我們的開(kāi)發(fā)效率。但是作為一個(gè)不能直接引用js npm包的語(yǔ)法 (支持的模式很繁瑣) ,同時(shí)小程序本身也沒(méi)有提供類(lèi)似redux、vuex的全局的狀態(tài)管理工具,這簡(jiǎn)直違反了mvc(mvvm)黨的一貫作風(fēng)。

于是想到了手寫(xiě)一個(gè)簡(jiǎn)單的全局狀態(tài)管理庫(kù),從各方面考察似乎可行,畢竟是一個(gè)接近vue的框架。

心路歷程如上。。。。。。還是不廢話了,上主菜 (可直接翻到文末查看代碼完整版) 。

小程序官方提供且推薦的demo中是把全局?jǐn)?shù)據(jù)放在app實(shí)例上——示例 ,咋一看似乎很接近我們的全局狀態(tài)管理需求,但這只是一個(gè)數(shù)據(jù)存儲(chǔ)方式,完全沒(méi)法做到響應(yīng)式狀態(tài)。

想想我們常見(jiàn)的需求,在個(gè)人中心頁(yè)點(diǎn)擊“去登錄”,跳轉(zhuǎn)到登錄頁(yè),測(cè)試一番騷操作,好不容易登錄成功了,返回個(gè)人中心,依舊是一個(gè)大大的“去登陸”按鈕在嘲諷著他/她,于是測(cè)試打了你一頓并讓你回去加班。

這時(shí)候你完全可以在onShow中使用 this.setData 刷新每一次頁(yè)面展開(kāi)......前提是你不怕繁瑣,同時(shí)愿意消耗更多的性能(sex power)。

所以開(kāi)始手寫(xiě),第一步,在項(xiàng)目中生成一個(gè) /store/sotre.js 文件。

再放兩個(gè)輪子中常用的方法

const _toString = Object.prototype.toString

function isFunction(obj) {
    return typeof obj === 'function' || false
}

function isObject(obj) {
    return _toString.call(obj) === '[object Object]' || false
}
復(fù)制代碼

createStore

全局狀態(tài)管理理索當(dāng)然需要一個(gè)全局的狀態(tài)存儲(chǔ),同時(shí)考慮使用react-redux的connect模式做綁定:

let _state = null

function connect(mapStateToData, mapMethodTopPage) {
    ...
}

/**
 * 創(chuàng)建store對(duì)象
 *
 * @param { Object } store
 * @returns { Object } _Store
 */
function createStore(state) {
    if (_state) {
        console.warn(
            'there are multiple store active. This might lead to unexpected results.'
        )
    }
    _state = Object.assign({}, state)
    // 這里返回_Store的原因是因?yàn)橄胪ㄟ^(guò)app實(shí)例直接獲取
    // const { connect, setState, createStore } = getApp().Store
    return _Store
}

const _Store = {
    connect,
    setState,
    createStore
}

module.exports = _Store


復(fù)制代碼

connect

現(xiàn)在的打算是將_state作為內(nèi)部存儲(chǔ),以免暴露出去被直接操作,無(wú)法做到響應(yīng)式(單一狀態(tài)樹(shù)只讀原則)。接下來(lái)的重點(diǎn)當(dāng)然是作為綁定數(shù)據(jù)和修改數(shù)據(jù)相互響應(yīng)了,先來(lái)connect:

let _state = null
let _subjects = [] // 用來(lái)存儲(chǔ)頁(yè)面實(shí)例對(duì)象
let _observers = [] // 用來(lái)存儲(chǔ)狀態(tài)響應(yīng)器

/**
 * 仿寫(xiě)react-redux的connect簡(jiǎn)單工廠
 *
 * @param { Function } mapStateToData
 * @param { Function } mapMethodTopPage
 * @returns { Function } pageConnect
 */
function connect(mapStateToData, mapMethodTopPage) {
    // mapStateToData接收state參數(shù),且必須返回一個(gè)綁定對(duì)象,key會(huì)被綁定到page實(shí)例的data中
    const dataMap = mapStateToData ? mapStateToData(_state) : {}
    // mapMethodTopPage接收setState和state參數(shù),且必須返回一個(gè)綁定對(duì)象,key會(huì)被綁定到page實(shí)例上
    const methodMap = mapMethodTopPage ? mapMethodTopPage(setState, _state) : {}
    return function(pageObject) {
        // 接收page對(duì)象
        // 遍歷綁定data
        for (let dataKey in dataMap) {
            if (pageObject.data) {
                if (pageObject.data[dataKey]) {
                    console.warn(
                        `page class had data ${dataKey}, connect map will cover this prop.`
                    )
                }
                pageObject.data[dataKey] = dataMap[dataKey]
            } else {
                pageObject.data = {
                    [dataKey]: dataMap[dataKey]
                }
            }
        }
        // 遍歷綁定method
        for (let methodKey in methodMap) {
            pageObject[methodKey] = methodMap[methodKey]
        }
        // 存儲(chǔ)onLoad、onUnload周期函數(shù),以便對(duì)其做改造
        const onLoad = pageObject.onLoad
        const onUnload = pageObject.onUnload
        pageObject.onLoad = function() {
            // 存儲(chǔ)page實(shí)例和事件響應(yīng)器,兩者保持同步,一個(gè)實(shí)例對(duì)應(yīng)一個(gè)響應(yīng)器
            if (!~_subjects.indexOf(this)) {
                // 首次load需要修改data
                this.setData(mapStateToData ? mapStateToData(_state) : {})
                _subjects.push(this)
                _observers.push(() => {
                    // mapStateToData生成新的mapData,并使用this.setData更新page狀態(tài)
                    this.setData(mapStateToData ? mapStateToData(_state) : {})
                })
            }
            // 觸發(fā)原有生命周期函數(shù)
            onLoad && onLoad.call(this)
        }
        pageObject.onUnload = function() {
            // 注銷(xiāo)響應(yīng)器
            const index = _subjects.indexOf(this)
            if (!~index) {
                _subjects.splice(index, 1)
                _observers.splice(index, 1)
            }
            // 觸發(fā)原有生命周期函數(shù)
            onUnload && onUnload.call(this)
        }
        return pageObject
    }
}
復(fù)制代碼

setState

狀態(tài)存儲(chǔ)和綁定都有了,現(xiàn)在需要一個(gè)修改state的方法:

復(fù)制代碼
/**
 * 所有的state狀態(tài)修改必須通過(guò)setState方法,以完成正常的響應(yīng)
 *
 * @param { Object | Function } state
 */
function setState(state) {
    // state 接收需要更新的state對(duì)象或者一個(gè)接收state的方法,該方法必須返回一個(gè)state更新對(duì)象
    let newState = state
    if (isFunction(state)) {
        newState = state(_state)
    }
    // 合并新?tīng)顟B(tài)
    _state = Object.assign(_state, newState)
    // 觸發(fā)響應(yīng)器
    _observers.forEach(function(observer) {
        isFunction(observer) && observer()
    })
}

完整的代碼

最后加上一些報(bào)錯(cuò)信息:

function isFunction(obj) {
    return typeof obj === 'function' || false
}

function isObject(obj) {
    return obj.toString() === '[object Object]' || false
}

let _state = null
const _subjects = [] // 用來(lái)存儲(chǔ)頁(yè)面實(shí)例對(duì)象
const _observers = [] // 用來(lái)存儲(chǔ)狀態(tài)響應(yīng)器

/**
 * 仿寫(xiě)react-redux的connect簡(jiǎn)單工廠
 *
 * @param { Function } mapStateToData
 * @param { Function } mapMethodTopPage
 * @returns { Function } constructorConnect
 */
function connect(mapStateToData, mapMethodTopPage) {
    if (mapStateToData !== undefined && !isFunction(mapStateToData)) {
        throw new Error(
            `connect first param accept a function, but got a ${typeof mapStateToData}`
        )
    }
    if (mapMethodTopPage !== undefined && !isFunction(mapMethodTopPage)) {
        throw new Error(
            `connect second param accept a function, but got a ${typeof mapMethodTopPage}`
        )
    }
    // mapStateToData接收state參數(shù),且必須返回一個(gè)綁定對(duì)象,key會(huì)被綁定到page實(shí)例的data中
    const dataMap = mapStateToData ? mapStateToData(_state) : {}
    // mapMethodTopPage接收setState和state參數(shù),且必須返回一個(gè)綁定對(duì)象,key會(huì)被綁定到page實(shí)例上
    const methodMap = mapMethodTopPage ? mapMethodTopPage(setState, _state) : {}
    return function(pageObject) {
        // 接收page對(duì)象
        if (!isObject(pageObject)) {
            throw new Error(
                `page object connect accept a page object, but got a ${typeof pageObject}`
            )
        }
        // 遍歷綁定data
        for (const dataKey in dataMap) {
            if (pageObject.data) {
                if (pageObject.data[dataKey]) {
                    console.warn(
                        `page object had data ${dataKey}, connect map will cover this prop.`
                    )
                }
                pageObject.data[dataKey] = dataMap[dataKey]
            } else {
                pageObject.data = {
                    [dataKey]: dataMap[dataKey]
                }
            }
        }
        // 遍歷綁定method
        for (const methodKey in methodMap) {
            if (pageObject[methodKey]) {
                console.warn(
                    `page object had method ${methodKey}, connect map will cover this method.`
                )
            }
            pageObject[methodKey] = methodMap[methodKey]
        }
        // 存儲(chǔ)onLoad、onUnload周期函數(shù),以便對(duì)其做改造
        const onLoad = pageObject.onLoad
        const onUnload = pageObject.onUnload
        pageObject.onLoad = function() {
            // 存儲(chǔ)page實(shí)例和事件響應(yīng)器,兩者保持同步,一個(gè)實(shí)例對(duì)應(yīng)一個(gè)響應(yīng)器
            if (!~_subjects.indexOf(this)) {
                // 首次load需要修改data
                this.setData(mapStateToData ? mapStateToData(_state) : {})
                _subjects.push(this)
                _observers.push(() => {
                    // mapStateToData生成新的mapData,并使用this.setData更新page狀態(tài)
                    this.setData(mapStateToData ? mapStateToData(_state) : {})
                })
            }
            // 觸發(fā)原有生命周期函數(shù)
            onLoad && onLoad.call(this)
        }
        pageObject.onUnload = function() {
            // 注銷(xiāo)響應(yīng)器
            const index = _subjects.indexOf(this)
            if (!~index) {
                _subjects.splice(index, 1)
                _observers.splice(index, 1)
            }
            // 觸發(fā)原有生命周期函數(shù)
            onUnload && onUnload.call(this)
        }
        return pageObject
    }
}

/**
 * 所有的state狀態(tài)修改必須通過(guò)setState方法,以完成正常的響應(yīng)
 *
 * @param { Object | Function } state
 */
function setState(state) {
    // state 接收需要更新的state對(duì)象或者一個(gè)接收state的方法,該方法必須返回一個(gè)state更新對(duì)象
    let newState = state
    if (isFunction(state)) {
        newState = state(_state)
    }
    // 合并新?tīng)顟B(tài)
    _state = Object.assign(_state, newState)
    // 觸發(fā)響應(yīng)器
    _observers.forEach(function(observer) {
        isFunction(observer) && observer()
    })
}

/**
 * 創(chuàng)建store對(duì)象
 *
 * @param { Object } store
 * @returns { Object } _Store
 */
function createStore(state) {
    if (_state) {
        console.warn(
            'there are multiple store active. This might lead to unexpected results.'
        )
    }
    _state = Object.assign({}, state)
    // 這里返回_Store的原因是因?yàn)橄胪ㄟ^(guò)app實(shí)例直接獲取
    // const { connect, setState, createStore } = getApp().Store
    return _Store
}

const _Store = {
    connect,
    setState,
    createStore
}

module.exports = _Store


復(fù)制代碼

確實(shí)夠簡(jiǎn)單吧,缺點(diǎn)是不支持模塊化和component,也沒(méi)有實(shí)現(xiàn)reducer和action,但是這些,我統(tǒng)統(tǒng)都不要 。 考慮現(xiàn)有需求和性能影響,目前沒(méi)有支持component和模塊化state——“小”程序方向靠攏(其實(shí)是懶)。

“小程序是一種不需要下載安裝即可使用的應(yīng)用,它實(shí)現(xiàn)了應(yīng)用‘觸手可及’的夢(mèng)想,用戶(hù)掃一掃或搜一下即可打開(kāi)應(yīng)用;也體現(xiàn)了‘用完即走’的理念,用戶(hù)不用關(guān)心是否安裝太多應(yīng)用的問(wèn)題。應(yīng)用將無(wú)處不在,隨時(shí)可用,但又無(wú)需安裝卸載。”

“微信之父”張小龍的這段話確定了小程序的開(kāi)發(fā)基調(diào)。鑒于小程序作為Web端的輕應(yīng)用,本身的特質(zhì)就決定了它不適合實(shí)現(xiàn)太過(guò)復(fù)雜的功能(為我的懶找到了官方支持)。



易優(yōu)小程序(企業(yè)版)+靈活api+前后代碼開(kāi)源 碼云倉(cāng)庫(kù):starfork
本文地址:http://www.kknew.com.cn/wxmini/doc/course/25018.html 復(fù)制鏈接 如需定制請(qǐng)聯(lián)系易優(yōu)客服咨詢(xún): 點(diǎn)擊咨詢(xún)
在線客服
易小優(yōu)
轉(zhuǎn)人工 ×