钩子与订阅系统是两种很爽工具类方法,码代码的时候一直用一直爽,直到钩子漫天飞,然后就重构。。。,不想重构需要斟酌的来使用它们
可以把小程序看做一个SPA的web应用,即可以内存数据共享,这就为我们的钩子系统提供了用武之地。可以跨路由页面使用钩子
我们为aotoo小程序开发了一套用起来很简单的钩子/订阅/数据存储的通用方法hooks,虽然是钩子的英文名,但它是一个混合物。
const core = require(‘components/aotoo/core’)
const lib = core.lib
const hooks = lib.hooks
// 实例
const hInst = hooks(‘hooks-name’) // 纯内存
// 或者
const hInst = hooks(‘hooks-name’, true) // 附带存储storage
//前者数据仅存储在内存
//后者在前者的基础上并通过wxstorage存储在本地
// api
// 数据部分
hInst.setItem(key, val)
hInst.getItem(key)
hInst.getInfo() // 返回该实例所有存储的数据或所有storage数据
hInst.append(key, val) // 追加数据,仅限JSON/ARRAY类型数据可以被追加
hInst.delete(key) // 删除某条数据
hInst.clear() // 强力删除数据,并等待内存回收
hInst.destory() // 只是清除内存数据,并等待内存回收
// 钩子部分
hInst.on(key, func)
hInst.off(key)
hInst.one(key, func)
hInst.once(key, func)
hInst.emit(key, param, context)
// 订阅发布部分
hInst.fire(key, param, context)
数据操作
日常数据操作,数据的增删改查
const core = require(‘components/aotoo/core’)
const lib = core.lib
const hooks = lib.hooks
const hInst = hooks(‘hooks-name’, true) // 一个钩子实例,附带存储storage
// JSON类数据
hInst.setItem('one', {title: '标题'}) // 初始化数据
hInst.append('one', {name: '张三'}) // => {title, name}
hInst.append('one', '李四') // => {title, name: '张三', rndKey: '李四'}
hInst.getItem('one') => // => {title, name}
hInst.delete('one') // => null
// 数组型
hInst.setItem('one', ['a']) // 初始化数据
hInst.append('one', {name: '张三'}) // => ['a', {name: '张三'}]
hInst.getItem('one') => // => ['a', {name: '张三'}]
hInst.delete('one') // => null
// 其他类型数据
// append无效
hInst.setItem('one', '你好') // 初始化数据
hInst.getItem('one') => // => 你好
hInst.delete('one') // => null
打开f12
的application,可以看到数据被存进了storage
钩子
日常钩子操作,挂钩子方法,触发执行钩子方法,要注意的是所有钩子方法都是同步执行
const core = require(‘components/aotoo/core’)
const lib = core.lib
const hooks = lib.hooks
const hInst = hooks('hooks-name', true) // 附带存储storage
// 恒有效的钩子方法
hInst.on('oneFun', function1) //挂载钩子方法
hInst.on('oneFun', function2)
hInst.on('oneFun', function3)
// 用完即删的方法,通过one来挂载
hInst.one('oneFun', function4)
// 只允许挂一个方法,最后进入的方法会被执行
hInst.once('twoFun', function5)
hInst.once('twoFun', function6)
hInst.once('twoFun', function7) // => 只有我才会被执行
hInst.emit('oneFun', {...}, context) // 无序遍历执行function1,2,3,4
hInst.emit('twoFun', {...}) // 只有function7被执行
emit
方法只允许传递一个JSON类数据, context是钩子方法执行的上下文(默认为null)
订阅/发布
日常订阅系统操作
// 恒有效的钩子方法
hInst.on('oneFun', function1) //挂载钩子方法
hInst.on('oneFun', function2)
hInst.on('oneFun', function3)
hInst.one('oneFun', function4)
hInst.fire('oneFun', {...}, context) // 遍历function1,2,3,4,所有方法用完即删
fire
方法只允许传递一个JSON类数据, context是钩子方法执行的上下文(默认为null)
源码
仅作为参看,因为aotoo有自己的运行环境
import {
isString,
isObject,
isArray,
isNumber,
isFunction,
formatQuery,
suid,
resetSuidCount,
} from './util'
class _hooks {
constructor(props={}) {
this.actions = {}
this.storeData = {}
this.storage = props.storage
}
destory() {
this.actions = null
this.storeData = null
// wx.clearStorageSync()
}
getInfo(){
return this.storage ? wx.getStorageInfoSync() : this.storeData
}
setItem(key, val){
try {
if (this.storage) {
wx.setStorageSync(key, val)
}
this.storeData[key] = val
} catch (error) {
console.warn(error);
}
}
getItem(key){
try {
let res
if (this.storage) {
res = wx.getStorageSync(key)
}
if (res) {
this.storeData[key] = res
}
return res
} catch (error) {
console.warn(error);
}
}
append(key, val){
if (this.storeData[key]) {
let sData = this.getItem(key)
if (isArray(sData)) {
sData = sData.concat(val)
} else if(isObject(sData)) {
if (isObject(val)) {
sData = Object.assign(sData, val)
} else {
sData[suid('random_')] = val
}
} else {
sData = val
}
this.setItem(key, sData)
} else {
this.setItem(key, val)
}
}
delete(key){
if (this.storage) {
wx.removeStorageSync(key)
}
this.storeData[key] = null
}
clear(){
this.destory()
wx.clearStorageSync()
}
// ========= 下面为钩子方法 ===========
on(key, cb) {
let myActions = this.actions
const hooksActionUniqId = suid('hooks_action_')
if (cb) {
cb['hooksActionUniqId'] = hooksActionUniqId
}
if (isString(key)) {
if (myActions[key]) {
myActions[key] = [].concat(myActions[key]).concat(cb)
} else {
myActions[key] = [cb]
}
}
}
off(key, fun) {
if (isString(key)) {
if (fun) {
let hooksActionUniqId = fun.hooksActionUniqId
if (hooksActionUniqId) {
let theFuns = this.actions[key]
let selectFunIndex
if (theFuns) {
theFuns.forEach(($f, ii) => {
if ($f['hooksActionUniqId'] == hooksActionUniqId) {
selectFunIndex = ii
}
})
if (selectFunIndex) {
theFuns.splice(selectFunIndex, 1)
}
}
}
} else {
delete this.actions[key]
}
}
}
emit(key, param, ctx=null) {
if (isString(key)) {
if (this.actions[key]) {
const vals = []
const funs = this.actions[key]
funs.forEach(fun => {
if (isFunction(fun)) {
const res = fun.call(ctx, param)
if (res) vals.push(res)
else {
vals.push(undefined)
}
if (fun.onlyonetime) {
this.off(key, fun)
}
// vals.push(fun.call(ctx, param))
}
})
if (vals.length) {
return vals
}
}
}
}
fire(key, param, ctx=null) {
const vals = []
function _fire(funcs=[]) {
if (funcs.length) {
const fun = funcs.shift()
const res = fun.call(ctx, param)
vals.push(res)
_fire(funcs)
} else {
return vals
}
}
if (isString(key) && this.actions[key]) {
_fire(this.actions[key])
if (vals.length) return vals
}
}
one(key, cb) {
if (key && typeof cb == 'function') {
let mycb = function() { return cb.apply(this, arguments) }
mycb.onlyonetime = true
}
this.on(key, cb)
}
once(key, cb) {
let myActions = this.actions
if (isString(key) && isFunction(cb)) {
myActions[key] = [cb]
}
}
}
let myhooks = {}
export function hooks(idf, storage) {
if (isString(idf)) {
if (!myhooks[idf]) {
myhooks[idf] = new _hooks({storage})
}
return myhooks[idf]
}
}
aotoo架构,https://www.agzgz.com
安装aotoo,https://juejin.im/post/5d11ce33f265da1b60291108
小程序demo