最近看到了技术公众号的推送文章,js的几大设计模式,闷着头看了一下。阅读大佬们的文章总是很有收货。用科学的方法来设计一个页面逻辑。比自己瞎摸索快速的多。先是仿着写了一个demo,后来碰到问题需要写一写逻辑,也算是刚好用的上。
什么是观察者模式?
Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。
Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。
了解这个模式之后发现好多框架在设计的时候都用到了这个模式,如:
- js 的事件机制 addEventListener
- vue的$emit(‘xx’)
demo
<button id='off'>解绑</button>
class observer {
constructor() {
this.events = {}
}
on(eventsType, handle) {
// 订阅事件
if (!this.events[eventsType]) this.events[eventsType] = []
this.events[eventsType].push(handle)
}
emit(eventsType, ...args) {
// 触发事件
if (this.events[eventsType]) {
this.events[eventsType].forEach((item, key, arr) => {
item.apply(null, args)
})
}
}
off(eventsType, handle) {
// 解除事件
if (this.events[eventsType]) {
this.events[eventsType].forEach((item, key, arr) => {
if (item == handle) {
this.events[eventsType].splice(key, 1)
console.log(eventsType, '解绑成功')
}
})
}
}
}
let testFun = function(data) {
console.log("demo加载好了啊", data)
}
// 初始化
let demo = new observer()
// 注册事件
demo.on('ready', testFun)
setTimeout(() => {
// 通知
demo.emit("ready", new Date())
}, 5000, );
$("#off").click(function() {
// 接触绑定
demo.off("ready", testFun)
})
问题:
公众号进入之后,页面的返回时返回上一页,但是有些页面不能返回上一层。比如:A=》B=》C ,在C页面的时候,单击返回,就会回到B页面,但是我不想让他去B,在C页面只能返回到A页面,这里就是问题了
解决思路
监听浏览器的返回事件,加上自定义的事件来控制页面的返回逻辑
跟观察者模式有什么关系?
我的理解:观察者模式是一个平台,允许同时存在好几种不同的事件,各自注册各自的,各自触发各自的。在C页面订阅一个返回按钮事件,在首页监听返回按钮触发,然后通知订阅返回事件的各个页面,触发各自的订阅事件。代码如下,公司项目,不方便贴出全部,只是粘贴部分:
// 工具类中写核心注册代码
export class BackEvent {
constructor() {
this.handles = {}
}
on(eventType, handle) {
// 订阅事件
if (!this.handles[eventType]) this.handles[eventType] = []
this.handles[eventType].push(handle)
}
emit(eventType, ...args) {
// 发布事件
if (this.handles[eventType]) {
this.handles[eventType].forEach((item, key, arr) => {
item.apply(null, args)
})
}
}
toUrl(url = '', title = '/#/') {
// 此方法是在页面加载前,往history中push一条数据,在A页面返回时就不会退出页面了
var state = { title, url }
window.history.pushState(state, state.title, state.url)
}
}
// main.js中挂载到vue的prototype中
import { BackEvent } from '@/common/js/index'
Vue.prototype.$backEvent = new BackEvent()
// APP.vue中监听浏览器返回事件,并触发事件
mounted() {
this.back()
},
methods: {
back() {
const that = this
that.$backEvent.toUrl()
window.addEventListener(
'popstate',
function(e) {
// 此处将router的name当做每个页面的唯一标识,实际使用中可以自定义变量
that.$backEvent.emit(that.$route.name)
},
false
)
}
}
// C页面中 订阅返回事件
mounted() {
this.$backEvent.on(this.$route.name, () => {
this.$router.push({
path: '/home/meeting'
})
})
},
结语
其实不使用这个模式,也能解决问题。或者可能是更简单,比如监听返回事件部分不变,改为触发vuex的变量,然后对应页面watch监听vuex变量来调用自己的返回函数,都能解决。只是这是个方向,实践的第一步,同时,也开辟了这个事件平台,如果再有类似的需求,也可以注册别的事件。方法很多。 设计模式博大精深,还是继续看吧!