先上代码
function cacheX(){
this.cache={
common:[]
};
}
cacheX.prototype={
addEvent:function(context,callback,id){
if(typeof id=="string"){
if(!this.cache[id]){
this.cache[id]=[];
}
this.cache[id].push({context:context,callback:callback,id:id});
}else{
this.cache["common"].push({context:context,callback:callback,id:id});
}
},
exec:function(event,id){
var i=0,arr=[];
if(typeof id=="boolean"){
if(id){//不管id执行所有
for(name in this.cache){
arr=arr.concat(this.cache[name]);
}
}else{//执行除了common之外所有的
for(name in this.cache){
if(name!="common"){
arr=arr.concat(this.cache[name]);
}
}
}
}else{
arr=id?(this.cache[id]?this.cache[id]:[]):this.cache["common"];
}
while(i
js中不少方法的执行依赖于同一个先决条件,或者说同一个事件,这个时候我们就可以将这些需要执行的事件统一缓存起来在一个事件里面统一执行。
这样做有不少好处
1.减少可见的事件数量以节约优化资源的使用
2.增加方法执行的可操作性控制方法执行的顺序
3.形成状态管理类的机制(统一缓存起来的数据作为状态管理的资源)
4.突破闭包等范围限制进行数据通信
下面举一些具体的例子
事件队列
1.点击事件click
单存某个子元素上的点击事件因为执行环境单一不具备太多重复可利用性,所以不适合这种模式
因为大多数事件具有冒泡的这个特性,所以很多时候我们都会在点击事件上做事件托管,但是父子元素上的简单事件托管任然不具备太多队列执行的价值
只有添加在document上的点击事件才具有使用队列价值,所有点击事件如果不阻止冒泡都会冒泡到document上,而对于点击事件我个人是不建议做阻止冒泡处理的,可以按照冒泡顺序在相应元素的事件里做过滤操作(比如下拉选择框,颜色选择框之类的弹窗需要在点击除特定元素外的位置后隐藏,这个功能逻辑事件一般都是在document的点击事件里面,如果部分元素冒泡阻止,那么这些功能就会失效)。像这种受众广的事件如果真的集中统一写在一起代码量会太大,不利于维护,这个时候就可以使用队列进行统一管理
/**
* 添加document点击事件承接方法
* */
global.domClick=new cacheX();
domClick.init();
以上代码中的global是基于webpack环境写成的,在开放环境中可以直接使用var声明
init()方法是内置于对象内部的click事件初始化方法,也可以独立出来,该方法执行的作用域是所有该集合中的方法
2.鼠标滚轮事件,mousemove,mouseup,mouseleave以及resize事件
所有这些受众广多个地方都需要使用的事件都可以使用队列缓存的形式来执行
/**
* 鼠标事件的总体监听
* */
global.mouseEvent=new cacheX();
//绑定鼠标事件
if(document.addEventListener){
document.addEventListener('DOMMouseScroll',mouseEve,false);
}
//IE及其他浏览器
window.onmousewheel = document.onmousewheel=mouseEve;
document.addEventListener("mousemove",mouseMove,false);
document.addEventListener("mouseup",mouseUp,false);
document.addEventListener("mouseleave",mouseLeave,false);
//可以调控执行顺序
function mouseEve(eve){
//先默认执行common集中的方法
mouseEvent.exec(eve);
//在执行除common外所有集中的方法
mouseEvent.exec(eve,false);
}
function mouseMove(eve){
mouseEvent.exec(eve,"mousemove");
}
function mouseUp(eve){
mouseEvent.exec(eve,"mouseup");
}
function mouseLeave(eve){
mouseEvent.exec(eve,"mouseleave");
}
//浏览器窗口的resize事件
global.Resize=new cacheX();
window.onresize=function(){
//可以做一些节流处理以避免卡顿现象
Resize..exec(null,true);
};
数据通信
基于缓存执行机制,我们可以把一些特殊作用域类的方法缓存起来,在需要传地数据的地方使用addEvent添加,在需要执行的时候手动调用exec执行并传递数据
基于vue的项目在组件之间通信的时候,父子通信使用的是props,子组件向父组件传递数据使用的是$emit,但是没有关联的组件之间通信这两种方式都不行,暂时先不论vue提供的vuex方案,使用这种队列的形式就可以解决这种问题
1.一对多数据传递
一个通知方法,多个接受端口
/**
* 统一的load完成状态管理
* 生成独立的实例
* */
global.Loaded=new cacheX();
/**
*在需要执行数据初始化任务的地方使用这个方法
*还可以顺带充当domready等事件的效
*@param data 传递过来的数据
*@param id 用于识别执行作用域的id 如果为true和false 作用域为最上面代码中标识的作用域
*this为当前作用域,传递过去之后可以在回调函数里面使用this来直接标识当前作用域,而不用在外面申明一个变量来承接作用域
*/
Loaded.addEvent(this,function(data,id){
//初始化选择数据
console.log(this)//this为执行Loaded.addEvent方法的方法的this,等同于与外部作用域一致
},this.iData.prid||this.prid);
/**
*执行数据通知操作
*除了第二个参数需要作为作用域识别外,其他参数均可以作为必要传递的数据
*/
Loaded.exec(data, id, extradata);
2.多对一的数据传递
一个接收端口 多个传递端口
代码与一对多相同,使用方式不同
数据状态管理
在vue项目中使用一对多的数据传递形式时,这个‘’多‘’因为作用域this作为参数传递了过来,使得缓存的数据里面有了所有的组件对象,如果所有需要的组件都使用这些方法进行赋值的话,那我们就可以添加方法根据特定的识别方案获取到任意想要的组件对象,可以操作执行任意组件内部的方法,甚至修改里面的数据
如果一对多和多对一同时使用
那么就可以有统一的值的集合保存方案,将初始化的值集合通过一对多的方式赋值给多;通过多对一的方式将修改后的值汇总到值集合
那么取值赋值的方法可以统一
后记
我没有看过vuex的使用与实现方式
但是感觉应该有相通的地方,可能就是一个简陋版的实现方案吧
只是单存的在实现时觉得这种事情自己也能做,而且也不难,而没有去考虑已经存在解决方案