小程序超级简单的跨页面跨组件通讯方式
非常简单小巧的跨页面跨组件通讯方式, 未压缩版4kb
实现很简单,
- 借助订阅发布模式实现跨页面跨组件的通讯
- 基于__wxWebviewId__和__wxExparserNodeId__实现只在当前的页面更新数据,减少性能消耗,并且切换到对应页面的时候,自动触发页面下的绑定方法
- 实现了哪怕先emit,后on的顺序也能正确触发绑定的函数,所以不用关心执行顺序
使用方式:
1. 在合适的位置使用 note.on(‘scope’, method, this),监听字段变化
2. 在任意位置使用 note.emit(‘scope’, data) 触发数据变更
API
note.get('scope') 获取数据,如果scope为空时获取所有数据
note.on(scope,method,this) 监听scope数据变化
note.emit(scope,data) 更改数据,并触发监听的方法
note.off(scope,this) 取消监听
话不多说,上代码
function isEmpty(obj: any) {
for (let key in obj) return false
return true
}
type Fn = (...args: any) => any;
interface NoteData {
[scopeName: string]: {
value: any;
watch: {
[webid: string]: {
[nodeid: string]: (never | Fn)[];
};
};
};
}
/**
* 小程序消息通知
* [@default](/user/default) 使用方法
* 1. 在合适的位置使用 note.on('scope', method, this),监听字段变化
* 2. 在任意位置使用 note.emit('scope', data) 触发数据变更
*
* [@method](/user/method) note.get('scope') 获取数据,如果scope为空时获取所有数据
*
* [@method](/user/method) note.on(scope,method,this) 监听scope数据变化
*
* [@method](/user/method) note.emit(scope,data) 更改数据,并触发监听的方法
*
* [@method](/user/method) note.off(scope,this) 取消监听
*/
class Note {
data: NoteData; // 数据存放
constructor() {
this.data = {};
}
/**
* 获取数据
* [@param](/user/param) scope 获取指定scope的value,不传时返回所有数据
*/
get(scope?: string) {
if (scope) return this.data[scope] ? this.data[scope].value : undefined;
let res: any = {};
Object.keys(this.data).map(key => {
res[key] = this.data[key].value;
});
}
/**
* 修改数据,会触发绑定的方法
* [@param](/user/param) scope 修改的节点
* [@param](/user/param) value 修改的数据
*/
emit(scope: string, value?: any) {
const self = this;
return new Promise((resolve: any, reject: any) => {
try {
// 数据中节点不存在
if (!self.data[scope]) self.data[scope] = { value, watch: {} };
else {
const page: any = getCurrentPages().pop();
Object.keys(self.data[scope].watch[page.__wxWebviewId__]).forEach(
nodeId => {
self.data[scope].watch[page.__wxWebviewId__][nodeId].forEach(
fn => {
fn(value, self.data[scope].value);
self.data[scope].value = value;
}
);
}
);
}
resolve(self.data[scope].value, value);
} catch (error) {
reject(error);
}
});
}
/**
* 绑定监听数据变化
* [@param](/user/param) scope 监听的节点
* [@param](/user/param) fn 监听的函数
* [@param](/user/param) ctx 当前页面或者自定义组件的this
*/
on(
scope: string | (string[]),
fn: any,
ctx: WxComponent | Page.PageInstance
): any {
const type = Object.prototype.toString.call(scope);
if (type === "[object String]") return this._on(scope as string, fn, ctx);
if (type === "[object Array]") {
return (scope as string[]).map((sc: string) => this._on(sc, fn, ctx));
}
}
/**
* 取消绑定监听
* @param scope 取消绑定的节点
* @param ctx 当前页面或者自定义组件的this
*/
off(scope: string | string[], ctx: WxComponent | Page.PageInstance): void {
const type = Object.prototype.toString.call(scope);
if (type === "[object String]") this._off(scope as string, ctx);
if (type === "[object Array]") {
(scope as string[]).map((sc: string) => this._off(sc, ctx));
}
}
_on(scope: string, fn: Fn, ctx: WxComponent | Page.PageInstance): any {
if (!this.data[scope]) this.data[scope] = { value: null, watch: {} };
if (!this.data[scope].watch[ctx.__wxWebviewId__])
this.data[scope].watch[ctx.__wxWebviewId__] = {};
if (!this.data[scope].watch[ctx.__wxWebviewId__][ctx.__wxExparserNodeId__])
this.data[scope].watch[ctx.__wxWebviewId__][
ctx.__wxExparserNodeId__
] = [];
this.data[scope].watch[ctx.__wxWebviewId__][ctx.__wxExparserNodeId__].push(
fn.bind(ctx)
);
return this.data[scope].value;
}
_off(scope: string, ctx: WxComponent | Page.PageInstance) {
try {
delete this.data[scope].watch[ctx.__wxWebviewId__][
ctx.__wxExparserNodeId__
];
if (isEmpty(this.data[scope].watch)) delete this.data[scope].watch;
if (isEmpty(this.data[scope].watch[ctx.__wxWebviewId__]))
delete this.data[scope].watch[ctx.__wxWebviewId__];
} catch (err) {}
}
}
const notice = new Note()
export default notice;
注: 其他小程序如字节小程序中只要有__wxExparserNodeId__和__wxWebviewId__类似的属性都可以使用