零、回顾
上节课我们主要学习了EventChannel对象,
这节课我们继续尝试整合用户自动登录,
并着手自定义实现一个观察者模式对象。
一、观察者模式
观察者模式是23个经典设计模式之一,
也是开发中经常使用的设计模式之一,
它的作用是当一个对象被修改的时候,
自动通知依赖它的对象,修改后的状态,
观察者模式,又被称为发布者-订阅者模式。
顾名思义,这个模式既可以订阅又可以发布,
实现该模式的对象,需要有一个方法提供订阅功能,
例如Subscribe、on这样的方法,
通过这个方法知道谁关心这个对象的状态,
还需要一个方法提供发布功能,
例如FireEvent、emit这样的方法,
告诉订阅者有新的状态产生了,。
这个模式最常使用的场景,就是事件派发者对象。
事件派发者对象,允许消费代码监听一个事件,
当这个事件在其他地方被派发的时候,
此处消费代码,将获取一个通知。
1.lib/event.js
//定义一个类
class Event{
//容器
cache;
//构造器,new event实例化的时候大概做一个什么事情
constructor(){
// this代表的是event的一个实例
this.cache={}
}
/**
* --订阅
* on事件:添加一个监听
* eventType:事件名称
* func:回调函数
* 这个事件可能存在多个事件,
* 一个事件对应多个执行函数
* 我们可能在多个地方监听一个事件
*/
on(eventType,func){
/*
this.cache[eventType] = func;
这样的话我们只能监听一个事件了,
就是你在另外一个地方如果再调用on的话,
就把前面的给它覆盖掉了
所以说这个地方我们需要的是把它变成一个,
我们这个对应的不是直接对应到func,
对应到一个map上,或者是一个数组。
*/
// this.cache[eventType] 如果不存在的话,是第一次的话,它其实等于一个数组。
( this.cache[eventType] || ( this.cache[eventType] = []) ).push(func);
}
/**
* 移除监听
*
*/
off(eventType,func){
if(func){
// 有的话先获取数据
let stack = this.cache[eventType];
// 如果拿到这个数组
if(stack && stack.length > 0){
// 数组遍历
for(let j=0;j<stack.length;j++){
// 直接做移除 索引,删除1个
if(stack[j] == func){
stack.splice(j,1)
break
}
}
}
}else{
// 移除全部
// 删除一个键值cache这样
delete this.cache[eventType];
}
}
/**
* 只监听一次
* on 与 off 的结合
*/
once(eventType,func){
// 不能使用箭头函数,只能是用function定义
function on(){
// 移除监听
this.off(eventType,on);
// 执行func方法
// 因为用的是function,所以这里可以用一个arguments参数对象,
// 是实参列表,
func.apply(this,arguments)
}
this.on(eventType,on);
}
/**
* --发布
* 发布订阅通知
*
*/
emit(eventType,...args){
const stack = this.cache[eventType];
// 判断是否存在 && 长度是不是大于1
if(stack && stack.length > 0 ){
// 如果是的话,加一个for循环
stack.forEach(item=>item.apply(this,args))
}
}
}
export default Event;
2.引用和使用Event模块
app.js
import Event from "./lib/event.js"
// getApp()获知App的实例
// getApp().globalEvent
App({
......
globalEvent:new Event(), //把Event new出来的一个实例,并挂载在App上,
......
})
pages/api/index.wxml
<view class="page-section">
<text class="page-section__title">3.8 Event</text>
<view class="btn-area">
<button bindtap="testEvent" type="primary">test event</button>
</view>
</view>
pages/api/index.js
//3.8 Event
testEvent(e){
const ge = getApp().globalEvent;
function func1(a,b){
console.log("a+b",a+b)
return a+b
}
ge.on("event1",func1);
ge.emit("event1",1,2);
},
编译
pages/api/index.js
//3.8 Event
testEvent(e){
const ge = getApp().globalEvent;
function func1(a,b){
console.log("a+b",a+b)
return a+b
}
ge.once("event1",func1);
ge.emit("event1",1,2);
ge.emit("event1",1,2);
},
编译
pages/api/index.js
//3.8 Event
testEvent(e){
const ge = getApp().globalEvent;
function func1(a,b){
console.log("a+b",a+b)
return a+b
}
ge.on("event1",func1);
ge.emit("event1",1,2);
ge.emit("event1",1,2);
},
编译
pages/api/index.js
//3.8 Event
testEvent(e){
const ge = getApp().globalEvent;
function func1(a,b){
console.log("a+b",a+b)
return a+b
}
ge.on("event1",func1);
ge.emit("event1",1,2);
ge.off("event1",func1);
ge.emit("event1",1,2);
},
编译
pages/api/index.js
//3.8 Event
testEvent(e){
const ge = getApp().globalEvent;
function func1(a,b){
console.log("a+b",a+b)
return a+b
}
ge.on("event1",func1);
ge.emit("event1",1,2);
ge.off("event1");
ge.emit("event1",1,2);
},
编译
有了事件对象,
接下来为了这个模块之间通讯方便,
我们将事件的对象绑定到全局的app对象上,
这样在每个页面里面都可以使用这个事件对象了
二、总结
这节课我们主要介绍了观察者模式,
并据此模式实现了一个event模块。
这个模块在我们接下来的开发中,
将有大大的作用。
下节课我们继续用户登录的自动整合,
尝试在wxp这个模块里面,
扩展出一个request3这样的一个接口。