前言
本来想定义为拦截器概念的…后来想想好像不对..应该是注入器概念..不过组件名都写好了 就懒得改了.
写这个小功能的原因很简单 目前开发方式都是所有的js放一个文件里了,那么如果我有多个页面,每个页面执行不同的函数 实现方式是不是很简单?
function indexCompontent(){
console.log('index')
}
if($('js-index').length>0){
indexCompontent();
}
用es6的语法写起来就更爽了,可以把每个函数拆开,但是如果我后台想传递一些参数…那是不是很蛋疼了,估计要绑定在html上 然后通过函数主动去获取..
div.js-index(data-user='{"name":"soul","uid":"2333"}')
script.
function indexCompontent(){
let s=$('.js-index').attr('data-user');
let data=JSON.parse(s);
}
这样写就有点蛋疼了..因为我需要主动的去获取html上的元素..一旦html元素id或者啥变了..就获取不到了…而且这种很不直观表达..那么是否有这样一种方式 我可以动态注入比如
window.startApp.addInterceptor('login-arg',".js-index",{a:"123"});
login-arg为自定义的参数辨识号,第二个为需要注入的组件名字,最后一个参数为传递的数据
编写注入器
因为这里依赖了Jquery,所以需要传递进入jQuery,为了兼容原有的组件,那么肯定是需要做一个转换的,这里的思路也比较简单 用两个对象来保存组件库和注入库
//组件库的大概形式
allCompontents={
'.js-index':[a,b,c]
".js-login":[a,b,d]
}
//注入库的大概形式
interceptorList={
'.js-index':{
'login-arg':{
a:'123'
}
},
".js-login":{
'xx-xx':{
x:"x"
}
}
}
首先为做适配器,把原有的组件列表转为新的组件列表..因为原有的可能就是一个组件对应一个函数,而新有的是一个组件对应多个函数
class InterceptorCompontent{
/**
*
* @param $ jQuery
* @param allCompontents 原有组件列表
*/
constructor($,allCompontents={}){
this.allCompontents=allCompontents;
this.$=$;
this.interceptorList={};
//转换单个func为array
if(this.allCompontents){
for (let item of Object.keys(this.allCompontents)){
if(item){
if(!this.$.isArray(this.allCompontents[item])){
this.allCompontents[item]=[this.allCompontents[item]];
}
}
}
}
}
}
编写填写组件和拦截器函数
这里也就是核心的函数了,不过根据上述的组件库和注入库列表来看应该就比较好理解了
/**
*
* @param obj 需要添加数据的对象
* @param name 数据的key
* @param data 数据的data
* @param customName 是否以对象的形式来添加组件
* @private
*/
__addFunc(obj,name,data,customName){
let current=obj[name];
//是否存在当前有对应的component
if(current){
if(!customName){
//数组的形式添加
if(!this.$.isArray(current)) {
//当前对应的component函数不为数组
obj[name] = [current];
//添加新的component执行函数
obj[name].push(data);
}else if(this.$.isArray(current)){
//当前对应的component函数为数组
obj[name].push(data);
}
}else{
//对象的形式添加
if(!this.$.isArray(current)&&typeof current =='object') {
//当前对应的component函数为对象
if(obj[name][customName]){
//如果已经存在当前自定义名称则扩展对象
Object.assign(obj[name][customName],data);
}else{
obj[name] ={
[customName]:data
};
}
}else if(this.$.isArray(current)){
//当前对应的component函数为数组
obj[name].push(data);
}
}
}else{
if(!customName){
//不存在对应的component
obj[name] = [];
//添加新的component执行函数
obj[name].push(data);
}else{
obj[name] ={
[customName]:data
};
}
}
}
/**
*
* @param name 组件名
* @param func 组件执行函数
*/
addCompontents(name,func){
this.__addFunc(this.allCompontents,name,func);
}
/**
* 添加拦截器
* @param {String} customName 自定义名
* @param {String} key 组件名
* @param {Object} data 必须为对象
*
*/
addInterceptor(customName,key,data){
if(!customName||!key||!data){
throw new Error(`必须传递 customName,key,data`);
return false;
}
this.__addFunc(this.interceptorList,key,data,customName);
}
编写init函数
__isExistCompontent(elem){
return this.$(elem).length>0?true:false;
}
init(){
for(let item of Object.keys(this.allCompontents)){
if(this.__isExistCompontent(`${item}`)){
//alert(`执行:${item}`,)
for(let func of this.allCompontents[item]){
//是否存在注入器
if(this.interceptorList[item]){
func(this.interceptorList[item]);
}else{
func();
}
}
}
}
}
最终的函数形式
export default class InterceptorCompontent{
/**
*
* @param $ jQuery
* @param allCompontents 原有组件列表
*/
constructor($,allCompontents={}){
this.allCompontents=allCompontents;
this.$=$;
this.interceptorList={};
//转换单个func为array
if(this.allCompontents){
for (let item of Object.keys(this.allCompontents)){
if(item){
if(!this.$.isArray(this.allCompontents[item])){
this.allCompontents[item]=[this.allCompontents[item]];
}
}
}
}
}
__isExistCompontent(elem){
return this.$(elem).length>0?true:false;
}
/**
*
* @param obj 需要添加数据的对象
* @param name 数据的key
* @param data 数据的data
* @param customName 是否以对象的形式来添加组件
* @private
*/
__addFunc(obj,name,data,customName){
let current=obj[name];
//是否存在当前有对应的component
if(current){
if(!customName){
//数组的形式添加
if(!this.$.isArray(current)) {
//当前对应的component函数不为数组
obj[name] = [current];
//添加新的component执行函数
obj[name].push(data);
}else if(this.$.isArray(current)){
//当前对应的component函数为数组
obj[name].push(data);
}
}else{
//对象的形式添加
if(!this.$.isArray(current)&&typeof current =='object') {
//当前对应的component函数为对象
if(obj[name][customName]){
//如果已经存在当前自定义名称则扩展对象
Object.assign(obj[name][customName],data);
}else{
obj[name] ={
[customName]:data
};
}
}else if(this.$.isArray(current)){
//当前对应的component函数为数组
obj[name].push(data);
}
}
}else{
if(!customName){
//不存在对应的component
obj[name] = [];
//添加新的component执行函数
obj[name].push(data);
}else{
obj[name] ={
[customName]:data
};
}
}
}
/**
*
* @param name 组件名
* @param func 组件执行函数
*/
addCompontents(name,func){
this.__addFunc(this.allCompontents,name,func);
}
/**
* 添加拦截器
* @param {String} customName 自定义名
* @param {String} key 组件名
* @param {Object} data 必须为对象
*
*/
addInterceptor(customName,key,data){
if(!customName||!key||!data){
throw new Error(`必须传递 customName,key,data`);
return false;
}
this.__addFunc(this.interceptorList,key,data,customName);
}
init(){
for(let item of Object.keys(this.allCompontents)){
if(this.__isExistCompontent(`${item}`)){
//alert(`执行:${item}`,)
for(let func of this.allCompontents[item]){
//是否存在注入器
if(this.interceptorList[item]){
func(this.interceptorList[item]);
}else{
func();
}
}
}
}
}
}
执行的话也比较简单
script.
window.startApp=new InterceptorCompontent($,allCompontents);
window.startApp.addInterceptor('login-arg',".js-login",{a:"123"});
window.startApp.init();//必须放到最后执行
不足
这个函数日常来用应该是没有什么问题了,但是如果出现了注入参数名相同的问题,那么这个是覆盖还是提示报错就有待讨论了.
添加组件的时候 如果传递的是一个数组,那么这里并没有做数组扁平化处理 仅仅是直接push而已,所以也会有一些问题。