这些错误不大,却很耽误时间。有时一个很小的问题,耽误1-2天都很正常。
把这些列出来,可以发现自己的缺点到底在什么地方:
2014-12-21
15,backbone的router和history
(1)router
(2)history
2014-12-19
14,上传文件控件一大堆问题
解决了两个bug
(1)防重复提交
解决方法一:url+参数逐个比较全部相同时不能提交两次;
//避免重复提交 var task = { caller: curOptions.caller, methond: curOptions.type, url: curOptions.url, args: curOptions.data }; if (this._isDuplicateRquest(task)) {return;} // 当做完防止重复提交校验之后,为url价格参数t if (curOptions.url.indexOf('?') > 0) { curOptions.url += "&t=" + (new Date()).getTime(); } else { curOptions.url += "?t=" + (new Date()).getTime(); } //ajax请求成功返回事件处理 curOptions.success = function (response, statusText, xhr) { _this._removeTask(task); if ( typeOf(customSuccess) === 'function' ) { if ( response.flag === '0' || response.flag === 0 ) { customSuccess(response.data, response, xhr); return; } else { if ( typeOf(customFail) === 'function' ) { customFail(response.msg, response, xhr); } else { alert((response.msg && response.msg.join('\r\n')) || '系统繁忙,请稍后再试'); } } } else { _this._defaultSuccess(response, statusText, xhr, curOptions); } }; //ajax请求发生错误事件处理 curOptions.error = function (xhr, statusText, errorThrown) { _this._removeTask(task); _this._defaultError(xhr, statusText, errorThrown, curOptions); }; Ajax.prototype._isDuplicateRquest = function (task) { for (var i = 0, len = this.taskQueue.length; i < len; i++) { var t = this.taskQueue[i]; if (task.caller === t.caller && task.url === t.url && task.methond === t.methond && $.param(task.args) === $.param(t.args)) { return true; } }; this.taskQueue.push(task); return false; }; Ajax.prototype._removeTask = function (task) { for (var i = 0, len = this.taskQueue.length; i < len; i++) { var t = this.taskQueue[i]; if (task.caller === t.caller && task.url === t.url && task.methond === t.methond && $.param(task.args) === $.param(t.args)) { this.taskQueue.splice(i, 1); break; } }; };
方法二:disabled按钮
用户提交后,disabled按钮,直到后端返回再enable,当然,后端只要返回就行。不论是成功还是失败。
(2)创建excel类型的feed,在IE下捕捉后端返回的异常
try { // IE浏览器走这个逻辑 if ($.type(response) === "string") { res = $.parseJSON(response); } //FF,Chrome走这个逻辑 else if ($.type(response) === "object") { res = response; } //奇怪的第三种情况 else { res = $.parseJSON($(response).text()); } } catch ( e ){ //创建失败 res = { 'flag' : 1 }; }
引用
历数uploader.js里出过的异常
(1)后端返回必须是content-type:text/html
(2)前端需要防止除file字段之外的其他字段多次重复添加。
(3)前端需要防止file字段提交一次后清空文件字段(isFileInputRefresh:false)
(4)防止用户多次提交,参加多条记录。防重复提交 或 disabled按钮。
(5)防止IE浏览器下报错。try catch
引用
历数双日历控件出过的异常
(1)span标签配对
(2)日历控件能够选择的时间范围是当天之后的。原因是:对当天以后的要加提示。修改控件,因为控件默认的是只能选择昨天的日期。
(3)控件没问题后,选择当前的提示语不对
(4)修改日历控件的默认选择,由昨天改为最近七天。
2014-12-10
转义字符又栽了一次。productDetail的key中带特殊字符,从页面获取值时应先unescapleHTML
正则表达式匹配qq号:
1,必须是数字,且是整数,且不能是负数
2,不能全0
3,不能以0开头,如果以0开头,需要去掉前面的0
uploader.js又有新问题:
就是重复提交的问题。
(1)File字段,增加一个参数isFileInputRefresh
true,提交完立即清空,避免重复提交
false,提交完不清空,需要重复提交
(2)其他字段,如name,indexType等也需要先判断是否已存在
已存在,更新值
不存在,添加
2014-12-04
13,转义字符
HTML的< >&"©分别是<,>,&,",©;的转义字符
XML只有5个转义符: < >& " '
例如:;;@@。::!!、?'‘’“”"=【】<><>《》~~•,
如果不转义,则会出现a标签出错。
详情参考: http://zccst.iteye.com/blog/2157743
2014-12-01
12, <meta http-equiv="X-UA-Compatible" content="IE=Edge">
解决了兼容性视图的问题
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
IE=edge告诉IE使用最新的引擎渲染网页,chrome=1则可以激活Chrome Frame
11,创建时多次订阅的问题
feed和product来回切换过程中,原有的feedMain没有destroy,导致多次初始化。
Router 里 判断feedMain 里面没有多次new
feedMain里 判断feedListManage,里面多次new(问题根源)
feedListManage里 初始化initialize时订阅
//监听事件
this.subs = [];
this.subs.push(PubSub.subscribe(TOPIC.FEED.FEEDTEMPLATE.CREATE, $.proxy(function(){
this.queryTable();
}, this)));
this.subs.push(PubSub.subscribe(TOPIC.FEED.FEEDTEMPLATE.MODIFY, $.proxy(function(){
this.queryTable();
}, this)));
this.subs.push(PubSub.subscribe(TOPIC.FEED.FEEDTEMPLATE.DELETE, $.proxy(function(){
this.queryTable();
}, this)));
//取消订阅
if(this.subs.length > 0){
for(var i = 0; i < this.subs.length; i++){
PubSub.unsubscribe(this.subs[i]);
}
}
2014-11-20
10,jQuery动态添加select的option在IE9下异常
错误的添加方式:(因为不兼容所有浏览器)
this.$el.find("select[name='updateFrequency']").append("<option value='3'>每隔数小时</option>"));
正确的添加方式:(因为兼容所以浏览器)
this.$el.find("select[name='updateFrequency']")[0].options.add(new Option("每隔数小时","3"));
9,IE浏览器封闭标签
双日历控件报错,IE7下浏览器左下角有两个字“取消”。
通过关键词搜索,发现是标签封闭错误。
8,content-type在IE浏览器中的错误解析
在上传文件组件中,后端返回content-type:text/javascript,在IE浏览器中会下载文件。文件的名字是actionName.js,内容是{"flag":0,"msg":"","data":[]};
如何解决?
通过设置content-type:text/html解决
原因:
在IE情况下,是表单提交,这时候需要设置表单的target为一个iframe,服务器端返回的数据将会回填到iframe中。在iframe中监听load事件,取iframe的内容,并解析。
此时如果iframe离的内容是html时,就当字符串处理了,所以可以成功解析。如果是text/javascript,IE会当成一段脚本,直接下载了。
7,在Backbone框架的项目中,创建的dialog到底要显示在哪里?
两种方式:
第一种是在调用的页面里写一个div作为父容器元素。也即是可以嵌套。
在new CrownCommonKeyPreview时传入el
var preview = new CrownCommonKeyPreview({ el : this.$el.find('div[name="crownCommonKeyPreview"]'), device : data.device, list : data.crownCommonKeyRowList });
CrownCommonKeyPreview收到options后,将el直接传给自己的view了。此时view的el就是传来的父容器。
var PreviewView = Backbone.View.extend({ events: { 'click .new_bt a' : 'demoClick', }, initialize: function(options){ this.model.bind('change:list', this.renderPreviewView, this); this.renderPreviewView(); }, ... });
el根本没有知名,但由于之前通过options传过来,所以是指定的父元素。
第二种是给 el 一个$("<div></div>")作为父容器,情况又分两种
(1)将this.view.$el.jdialog();作为一个弹窗
上代码:
/** * Class DeadLink */ var DeadLink = function(options){ this.options= options || {}; this.model = new Model(this.options.modelOptions || {}), this.view = new View($.extend(true, {model: this.model}, this.options.viewOptions||{})); } DeadLink.prototype.showInDialog = function(){ this.dialog = this.view.$el.jdialog({ title: this.options.dialogTitle == undefined ? '死链URL优化':this.options.dialogTitle, width : '820px', destroyOnClose : true, destroyContent: true, buttons: { } }); } DeadLink.prototype.destroy = function(){ if(this.view && this.view.destroy && typeof this.view.destroy == 'function'){ this.view.destroy(); } }
再来看view
var View = Backbone.View.extend({ el: '<div></div>', events: { //'click a[name="tab"]': 'changeContent', 'click a[name="batchReCheck"]' : 'batchReCheck', 'click a[name="batchModifyUrl"]' : 'batchModifyUrl', 'click a[name="downloadMaterial"]': 'downloadMaterial', 'click a[name="downloadUrl"]' : 'downloadUrl', 'click th input' : 'selectAll', 'click td input' : 'selectOne' }, initialize: function(){ //画上方黄色提示话术 this.model.bind('change:deadLinkCount', this.renderCount, this); this.render(); }, });
(2)将el直接append到body里
/*------------------华丽的分割线表明好久没有更新了---------------*/
6,keydown, keyup区别(onpropertychange)
keydown 没有实时将输入的内容,放到输入框。
keypress 没有实时将输入的内容,放到输入框。
keyup 将输入的内容实时放到输入框。
原因:
触发顺序: keydown --> keypress --> keyup
可以在这途中被中断。
结论:keydown和keypress,还没有将当前输入内容放入input框,所以也无法获取最新的值。
//IE浏览器兼容性。成功,在键盘松开时将值放到input,然后获取时已是最新 if($.browser.msie){ var inputArr = this.$el.find("input.colName, input.colurl"); for(var i = 0; i < inputArr.length; i++){ $(inputArr[i]).on('keyup', function(){ _this.model.set('crownListRowList', _this.getSrcData()); }); } } //IE浏览器兼容性。失败,属性太强 if($.browser.msie){ var inputArr = this.$el.find("input.colName, input.colurl"); for(var i = 0; i < inputArr.length; i++){ $(inputArr[i])[0].attachEvent("onpropertychange",function(){ this.getSrcData(); }); } }
onpropertychange 除非置为disabled,否则任何变化都会触发。
缺点是:任何属性都会变化,不够灵活。比如想在input输入框加验证。这次就会触发对应的回调函数。
5,backbone子类调用的问题
应该放到render里调用。而不是放到initialize中。
4,backbone的new View(参数),在View的initialize中如何拿到
var view = new View({
model:model,
data:data
});
var View = Backbone.extend.View({
initialize:function(){
this.model.set(this.options.data);
}
});
结论:通过this.options可以获取传递的参数
3,this作用域的问题
$.each(json,function(index, item){
//此时的this是item,不再是外面的this
});
if($.browser.msie){ var inputArr = this.$el.find("input.colName, input.colurl"); for(var i = 0; i < inputArr.length; i++){ $(inputArr[i])[0].attachEvent("onpropertychange",function(){ _this.model.set({crownListRowList: eval(_this.crownSheet.getEditedDataForPreview())}); }); } }
2,IE浏览器下实时预览用户在input输入框中输入的数据
在非IE浏览器下,用input事件
在IE浏览器想,用onpropertychange事件
再加上paste,就完美了。
但是,经查找,onpropertychange属性监听不到的情况:
1,input是disabled时。
2,使用jQuery或其他手段向input设值。
尽管我目前够用了。查到的解决办法只有一个那就是定时监控。
当input获取到焦点时,定时器开启,每隔0.1秒去读input中最新的结果。
一旦input失去焦点,则清除定时器。
1,拼接JSON串耗时较长,完全是试着来的
//在另一个函数里 _constructor.prototype.bindXX = function(){ this.colNames = [], this.colurls = []; var tblObj = null; if(this.device == 1){ tblObj = this.$el.find("#form_pc"); }else if(this.device == 2){ tblObj = this.$el.find("#form_mobile"); } var trs = tblObj.find("tr:visible"); for (var i = 1; i < trs.length; i++) { var rowNameArr = [], rowUrlArr = [], tds = $(trs[i]).find("td:visible"); for (var j = 1; j < tds.length; j++) { rowNameArr.push($(tds[j]).find("input.colName")); rowUrlArr.push($(tds[j]).find("input.colurl")); } this.colNames.push(rowNameArr); this.colurls.push(rowUrlArr); } } // var str = "["; for (var i = 0; i < this.colNames.length; i++) { var rowStr = "{"; for (var j = 0; j < this.colNames[i].length; j++) { rowStr += (rowStr=="{"?("col"+(j+1)+"Name:"):(",col"+(j+1)+"Name:")) + "'"+$.trim($(this.colNames[i][j]).val())+"'"; rowStr += ",col"+(j+1)+"url:" + ( $(this.colurls[i][j]).prop("disabled") ? "''" : "'"+$.trim($(this.colurls[i][j]).val())+"'" ); } rowStr += "},"; str += rowStr; } str = (str.slice(0,str.length-1) + "]"); //return eval(str); return str;
二维json的格式是:
[{k11:v11, k12:v12, ... },
{k21:v21, k22:v22, ... },
{k31:v31, k32:v32, ... },
...
{kn1:vn1, kn2:vn2, ... },
]
拼接完之后是字符串,还需要用eval转成对象,才能使用。