简单讲下这次写一个插件的背景:在协助同事完成数据导入工作的情况要得到一个需求,需求很简单,就是实现从Excel里复制一段内容然后可以将内容自动识别填写到表单里。虽然描述如此天马行空,也不明确有多少人有这样需求,但发现实现并不是难事。
作为一个码农,习惯性各种插件堆一起,然后写完代码,打包成遨游插件,同事欣喜若狂地用了起来,但用着用着各种问题飞奔而来。以下是我总结我开发的经历:
- 第一版,导入JQ包及写了一个JS文件,使用正则表达式简单分解字符串,及使用LocalStorage缓存内容,打包成遨游浏览器插件。(一开始我是设计用iframe的,但有跨域问题,出现跨域问题后我就终止了用iframe)
-
第二版,将第一版实现所有功能的JS制作成通用功能并以在线的形式利用导航条脚本注入方式加载到页面,处理了浏览器的兼容性IE8+、FF3.6+、Chrome等。
-
第三版,改造第二版,解决脚本对原页面污染问题,将所有JS以模块方式加载,使用Seajs加载。(我用了当前页面脚本注入和CSS加载,发现脚本存在执行污染问题,然后我用了考虑用RequireJS或Seajs解决,后来选了Seajs)
-
第四版,改造第三版,使用iframe对插件的功能HTML代码、CSS代码与JS代码隔绝。
其实作为一个程序员,如果只考虑需求,而不追求自己代码的改进,第一个版本基本可以满足需求了。但不重构的话,达不到通用的要求了。
然后css因为没办法,加载了bootstrap库,必须污染,后来参考了firebug-lite,它是用iframe的,读了源码后,发现又被坑了,它是用iframe的但事件那些都原生JS写的,而我用JQ,应该说是JQ坑我,JQ会将iframe渲染成同一个执行域这样就坑了,我在iframe加载的CSS可以了,但JS却变成了在父域加载。国内搜到的基本是这种$("#mainiframe").contents().find("someID").html()就是contents()这个方法,这样执行的$等价于$(document).find(),我花了一周末去解决,最后在Google搜到了结果,所以执行的window对象是父文档,所有效果被应用到了父文档,以后我开发插件尽量用iframe隔绝CSS和JS。我的远大理想是以后一些功能都做成挂件,就业务逻辑无关的功能,类似于分享条那样。
下面列出一些参考代码。
第一版的核心参考代码
function SiseInsert(){ //获取配置 this.getConfig=function(){ var init=globalConfig; if(window.localStorage.getItem("SiseInsert")==null){ return init; } init=$.evalJSON(window.localStorage.getItem("SiseInsert")); return init; } //设置配置 this.setConfig=function(config){ window.localStorage.setItem("SiseInsert",$.toJSON(config)); } this.displayConfig=function(){ var conf=this.getConfig(); $("#hackEgg input[type='text']").eq(0).val(conf.total); $("#hackEgg input[type='text']").eq(1).val(conf.current); $("#hackEgg input[type='text']").eq(2).val(conf.delay); $("#hackEgg input[type='text']").eq(3).val(conf.status); $("#hackEgg input[type='text']").eq(4).val(conf.regex); $("#hackEgg input[type='text']").eq(5).val(conf.replace); $("#hackEgg textarea").eq(0).val($.toJSON(conf.datasource)); } this.select=function(name,value){ $("select[name='"+name+"']").find("option[text='"+value+"']").attr("selected",true); } this.input=function(name,value){ $("input[name='"+name+"']").val(value); } this.radio=function(name,index){ $("input[name='"+name+"']").eq(parseInt(index)).attr("checked",'checked'); } this.insert=function(target,name,value){ switch(target){ case "input": this.input(name,value); break; case "select": this.select(name,value); case "radio": this.radio(name,value); break; } } this.insertAll=function(list){ for(i=0;i<list.length;i++){ this.insert(list[i].target,list[i].name,list[i].value); } } } function pageInit(){ var operator=new SiseInsert(); var text='\ <div id="hackEgg" style="width:150px;height:1085px;position:absolute;left:0;top:0;background:#fff;z-index:10000;">\ <div>总数<input style="width:100px" type="text"></div>\ <div>当步<input style="width:100px" type="text"></div>\ <div>延时<input style="width:100px" type="text"></div>\ <div>状态<input style="width:100px" type="text"></div>\ <div>正则<input style="width:100px" type="text"></div>\ <div>替换<input style="width:100px" type="text"></div>\ <div><input type="button" value="读取" /><input type="button" value="更新" /><input type="button" value="重建" /></div>\ <div>数据<textarea style="width:100px" type="text"></textarea></div>\ <div><input type="button" value="更新数据源" /></div>\ </div>'; $("body").append(text); operator.displayConfig(); $("#hackEgg input[type='button']").eq(0).click(function(){ operator.displayConfig(); }); $("#hackEgg input[type='button']").eq(1).click(function(){ var conf=operator.getConfig(); //conf.total=$("#hackEgg input").eq(0).val(); conf.current=parseInt($("#hackEgg input").eq(1).val()); conf.delay=parseInt($("#hackEgg input").eq(2).val()); conf.status=parseInt($("#hackEgg input").eq(3).val()); conf.regex=$("#hackEgg input").eq(4).val(); conf.replace=$("#hackEgg input").eq(5).val(); operator.setConfig(conf); }); $("#hackEgg input[type='button']").eq(2).click(function(){ window.localStorage.removeItem("SiseInsert"); var conf=operator.getConfig(); operator.setConfig(conf); }); $("#hackEgg input[type='button']").eq(3).click(function(){ var conf=operator.getConfig(); var str=$("#hackEgg textarea").eq(0).val(); var regex=new RegExp(conf.regex,"gm"); str=str.replace(regex,conf.replace); str=str.replace(/[\r\n]/gm,""); str=str.replace(/,$/,""); str=str.replace(/""/gm,"\""); str="["+str+"]"; conf.datasource=$.evalJSON(str); conf.total=conf.datasource.length; conf.current=0; operator.setConfig(conf); operator.displayConfig(); }); } /*********************************华丽分割线**************************/ var globalConfig={ total:0, current:0, delay:0, status:0, regex:'^([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)\\t([^\\t]*?)$', replace:'[{"target":"input","name":"applyName","value":"$1"},{"target":"input","name":"manName","value":"$2"},{"target":"select","name":"manCardType","value":"$3"},{"target":"input","name":"manCardNo","value":"$4"},{"target":"select","name":"PropertySelection","value":"$5"},{"target":"input","name":"birth","value":"$6"},{"target":"input","name":"manMajor","value":"$7"},{"target":"select","name":"PropertySelection_0","value":"$8"},{"target":"input","name":"inputDate1","value":"$9"},{"target":"input","name":"inputDate2","value":"$10"},{"target":"input","name":"manSchool","value":"$11"},{"target":"input","name":"manGraduationTime","value":"$12"},{"target":"input","name":"manLinktype","value":"$13"},{"target":"input","name":"orgName","value":"$14"},{"target":"input","name":"trainProject","value":"$15"},{"target":"input","name":"inputDate3","value":"$16"},{"target":"input","name":"inputDate4","value":"$17"},{"target":"input","name":"trainMoney","value":"$18"},{"target":"select","name":"jobstatus","value":"$19"},{"target":"input","name":"jobCorpname","value":"$20"},{"target":"radio","name":"size","value":"$21"}],', datasource:[] }; $(function(){ if(window.location.href.indexOf("login.html")!=-1){ var str=''; setTimeout(function(){ $("#loginId").html(str); },0); } var operator=new SiseInsert(); var conf=operator.getConfig(); if(window.location.href.indexOf("Trainedit.html")!=-1){ pageInit();//初始化页面 conf.total=conf.datasource.length; //当前步有效 if(conf.total>conf.current){ if(conf.status==1){ var person=conf.datasource[conf.current]; operator.insertAll(person); setTimeout(function(){ conf.current=conf.current+1; operator.setConfig(conf); //提交 $("#manNo").val("身份证验证通过") $("#Submit_0").eq(0).click(); },conf.delay); } } else{ if(conf.status==1){ alert("已完成"); } } } else if(window.location.href.indexOf("TrainCorpList,SrestoreList.html")!=-1){ if(conf.status==1){ window.location.href="Trainedit.html" } else if(conf.status==5000){ window.close(); } } else if(window.location.href.indexOf("TrainCorpList.html")!=-1){ pageInit();//初始化页面 if(conf.status==5000){ var all=$("a[href^='/pages/train/org/TrainCorpList_delete']"); $.each(all,function(i,c){ window.open($(c).attr("href"),'','fullscreen=0,scrollbars=0'); }); } } });
最终版的参考代码结构
最终版的代码结构有点啰唆,使用请猛点这里,详细代码请开浏览器调试!
相关推荐
标题:“浅谈jQuery的应用” 知识点: 1. jQuery简介:jQuery是一个继prototype之后的优秀JavaScript框架,由John Resig创建于2006年初。它简化了JavaScript以及Ajax编程,以“write less, do more”为宗旨,用更...
2. **插件开发**:Google Earth Web Plugin使得开发者能够在网页中嵌入Google Earth,用户无需安装完整的Google Earth客户端即可查看和操作地球仪。 3. **KML与KMZ文件**:这两种文件格式是Google Earth用于存储地理...
虽然Java可能不是游戏开发的首选语言,但Unity引擎支持Java插件,允许开发者利用Java编写游戏逻辑。此外,LWJGL(Lightweight Java Game Library)等库提供了对图形、音频和输入设备的低级访问,适合开发2D游戏和...
"浅谈JavaScript库——jQuery,ExtJs的对比研究.pdf" 本文简要介绍了目前流行的JavaScript库,并对其中较为流行的两个库jQuery和ExtJs进行了较详细的介绍和对比研究。本文首先简要介绍了JavaScript库的概念和特点,...
3. 降低成本:Cordova 可以使用标准的 Web 技术,降低开发和维护成本。 Cordova 的缺点 1. 性能问题:Cordova 应用程序的性能可能不如原生应用程序。 2. 离线模式支持:Cordova 应用程序需要联网才能正常工作,但 ...
Django提供了一个全功能的“一站式”解决方案,几乎包含了Web开发所需的所有组件,但这种便利性是以牺牲组件间的松耦合为代价的,可能会对第三方插件的兼容性造成影响。Tornado底层利用event loop来实现异步请求处理...
HTML5是下一代超文本标记语言,它在2004年由万维网联盟(W3C)提出,旨在简化Web开发并增强网络应用的功能。HTML5的发展与现状是现代互联网技术的重要组成部分,对于软件技术专业人员来说,理解其演变、现状及未来...
### OFBIZ 4.0 入门指南 #### 一、OFBIZ 4.0 开发环境的搭建 ...此外,还需要安装 Subclipse、Mylyn 和 Mylyn-Extras 等插件来辅助开发过程。一旦开发环境准备就绪,就可以开始探索 OFBIZ 的汉化及模块开发等功能了。
总的来说,Cordova 是一种适用于快速开发和轻量级应用的解决方案,对于希望利用 Web 技术进行多平台开发的团队而言,是一个非常有价值的工具。不过,在选择使用 Cordova 之前,需要权衡其性能、用户体验和项目需求,...
"浅谈Java技术学习方法.pdf" Java是一种简单易用、完全面向对象、有平台无关性、安全可靠的开发工具。自1995年正式问世以来,Java的快速发展已经让整个Web世界发生了翻天覆地的变化。Java技术和应用发展很快,在...
Creo是家电行业产品三维模型通用化设计软件,它提供了Pro/Toolkit、JLINK、Weblink.VB等多种二次开发工具,企业可以根据需求使用这些工具进行定制化开发,并将开发的插件嵌入到Creo三维设计环境中,实现设计和审查...
学习和熟练掌握Webpack配置和插件的使用,可以显著提升开发效率,优化应用性能。随着技术的发展,Webpack生态系统不断壮大,新的插件和功能也在不断涌现,所以保持学习和更新知识是非常重要的。
6. **Web Storage API**:提供本地存储机制,使得离线Web应用成为可能,且存储容量较大,安全性更高。 7. **Drag and Drop API**:简化了拖放操作,使得用户可以轻松地在网页元素间移动内容。 CSS3 的新特性主要...
被动监控模式适用于远程主机位于防火墙内部的情况,远程监控中心收集信息后,通过nagios客户端传递给中心服务器,再在web界面上显示。 主动监控的具体工作流程如下: 1. 中心服务器运行Nagios应用,根据配置文件...
- **易于部署**:利用现有Web服务器,无需特殊服务器软件。 **劣势**: - **延迟**:相比RTMP,HLS的延迟较大,不适合实时交互场景。 - **文件管理**:大量短小的文件可能增加服务器存储和管理的复杂性。 - **请求...
接下来,你需要安装PDT插件。有两种方式:在线安装和离线安装。在线安装可以通过Eclipse的内置更新机制完成,但可能需要较长时间。如果你选择离线安装,可以从Eclipse的发布站点下载包含PDT的Eclipse版本。 为了...
- Express:Node.js的Web应用框架,用于构建生产启动程序。 - FSGit:文件系统相关的操作。 项目目录结构清晰,`src`目录下包含各个页面的入口文件和公共资源,`webpackConfig`目录下存放处理这些资源的配置文件,`...
在开发Web应用时,Visual Studio 2019 提供了对Vue.js框架的强大支持。本文将深入探讨在Visual Studio 2019中创建Vue项目的目录结构,这对于理解和管理Vue项目至关重要。 Vue项目的目录结构通常遵循标准的前端工程...