Created
November 16, 2021 11:05
-
-
Save SakuOtonashi/c98aa31d2b5fdc82ba0bcdb1eb8e07cd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { getUnreadMessageCount } from '../services/message' | |
export class State { | |
message = { unreadCount: 0 } | |
async getUnreadMessageCount() { | |
this.message.unreadCount = await getUnreadMessageCount() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import stateStore from '../../stores/state' | |
Page({ | |
data: { | |
// 也可以只指定部分属性同步时也只会同步这一部分 | |
stateData: stateStore.data, | |
}, | |
onLoad() { | |
// @ts-ignore | |
this._ssViewId = stateStore.connectAndUpdate('stateData', this) | |
}, | |
onUnload() { | |
// @ts-ignore | |
stateStore.disconnect(this._ssViewId) | |
}, | |
getUnreadCount() { | |
stateStore.getUnreadMessageCount() | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { State } from '../models/state' | |
import { WeStore } from './utils' | |
class StateStore extends WeStore<Pick<State, 'message'>> { | |
state: State | |
constructor() { | |
super() | |
this.state = new State() | |
this._computeData() | |
} | |
private _computeData() { | |
this.data = { | |
message: this.state.message, | |
} | |
} | |
async getUnreadMessageCount() { | |
await this.state.getUnreadMessageCount() | |
this._computeData() | |
this.update() | |
} | |
clearAllInfo() { | |
this.state.message = { unreadCount: 0 } | |
this._computeData() | |
this.update() | |
} | |
} | |
// 可以和多个页面组件联结实现自动绑定共享数据 | |
const stateStore = new StateStore() | |
export default stateStore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 参考 [westore](https://github.com/Tencent/westore) | |
// 只做浅层比较 | |
export function diffData<V extends Record<string, any>, K extends Partial<V>>( | |
current: K, | |
previous: V | |
) { | |
const patch: Partial<V> & Record<string, any> = {} | |
;(Object.keys(previous) as (keyof V)[]).forEach((key) => { | |
const curVal = current[key] | |
const preVal = previous[key] | |
if (curVal !== undefined && curVal !== preVal) { | |
if (Array.isArray(curVal) && Array.isArray(preVal)) { | |
if ( | |
curVal.length >= preVal.length && | |
curVal.length <= preVal.length * 1.25 | |
) { | |
// 浅层数据里的数组类型仅在增加和修改少量成员的情况下会拆出来单独更新 | |
const changes: number[] = [] | |
;(curVal as any[]).forEach((item, index) => { | |
if (preVal[index] !== item) { | |
changes.push(index) | |
} | |
}) | |
if (changes.length * 5 <= curVal.length) { | |
changes.forEach((i) => { | |
// @ts-ignore | |
patch[key + '[' + i + ']'] = curVal[i] | |
}) | |
return | |
} | |
} | |
} | |
patch[key] = curVal | |
} | |
}) | |
return patch | |
} | |
export class WeStore<V extends Record<string, any>> { | |
private _weStoreViews: Record<string, QuasiView<Partial<V>>> = {} | |
private _weStoreViewId: number = 0 | |
public data = {} as V | |
connect<T extends string>( | |
prop: T, | |
view: PageOrComponent<T, Partial<V>>, | |
viewId?: string | number | |
) { | |
const quasiView = newQuasiView(prop, view) | |
const viewId2 = viewId || this._weStoreViewId++ | |
this._weStoreViews[viewId2] = quasiView | |
return viewId2 | |
} | |
disconnect(viewId: string) { | |
delete this._weStoreViews[viewId] | |
} | |
connectAndUpdate<T extends string>( | |
prop: T, | |
view: PageOrComponent<T, Partial<V>>, | |
viewId?: string | number | |
) { | |
const viewId2 = this.connect(prop, view, viewId) | |
this.update(viewId2) | |
return viewId2 | |
} | |
update(viewId?: string | number) { | |
if (viewId) { | |
updateView(this._weStoreViews[viewId], this.data) | |
} else { | |
Object.values(this._weStoreViews).forEach((view) => { | |
updateView(view, this.data) | |
}) | |
} | |
} | |
} | |
export interface PageOrComponent< | |
T extends string, | |
V extends Record<string, any> | |
> { | |
data: { [K in T]: V } & Record<string, any> | |
setData: ( | |
data: { [K in T]: any } & Record<string, any>, | |
callback?: () => void | |
) => void | |
} | |
// 视图简化的抽象接口 | |
interface QuasiView<V extends Record<string, any>> { | |
getData: () => V | |
setData: ( | |
data: Partial<V> & Record<string, any>, | |
callback?: () => void | |
) => void | |
} | |
function newQuasiView<T extends string, V extends Record<string, any>>( | |
prop: T, | |
view: PageOrComponent<T, V> | |
) { | |
const quasiView: QuasiView<V> = { | |
getData() { | |
return view.data[prop] | |
}, | |
setData(data, callback) { | |
const subData: any = {} | |
Object.keys(data).forEach((key) => { | |
subData[prop + '.' + key] = data[key] | |
}) | |
view.setData(subData, callback) | |
}, | |
} | |
return quasiView | |
} | |
function updateView<V extends Record<string, any>>( | |
quasiView: QuasiView<V>, | |
data: Partial<V> & Record<string, any>, | |
callback?: () => void | |
) { | |
const patch = diffData(data, quasiView.getData()) | |
quasiView.setData(patch, callback) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment