2014年7-12月 犯的几个小错误

作者:zccst

这些错误不大,却很耽误时间。有时一个很小的问题,耽误1-2天都很正常。

把这些列出来,可以发现自己的缺点到底在什么地方:

2014-12-21
[b]15,backbone的router和history[/b]
(1)router


(2)history


2014-12-19

[b]14,上传文件控件一大堆问题[/b]
解决了两个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
};
}



[quote]历数uploader.js里出过的异常[/quote]
(1)后端返回必须是content-type:text/html
(2)前端需要防止除file字段之外的其他字段多次重复添加。
(3)前端需要防止file字段提交一次后清空文件字段(isFileInputRefresh:false)
(4)防止用户多次提交,参加多条记录。防重复提交 或 disabled按钮。
(5)防止IE浏览器下报错。try catch

[quote]历数双日历控件出过的异常[/quote]
(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
[b]13,转义字符[/b]

HTML的< >&"©分别是<,>,&,",©;的转义字符
XML只有5个转义符: < >& " &apos;
例如:;;@@。::!!、?'‘’“”"=【】<><>《》~~•,
如果不转义,则会出现a标签出错。
详情参考:[url]http://zccst.iteye.com/blog/2157743[/url]


2014-12-01
[b]12, <meta http-equiv="X-UA-Compatible" content="IE=Edge">[/b]
解决了兼容性视图的问题

<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
IE=edge告诉IE使用最新的引擎渲染网页,chrome=1则可以激活Chrome Frame

[b]11,创建时多次订阅的问题[/b]
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
[b]10,jQuery动态添加select的option在IE9下异常[/b]
错误的添加方式:(因为不兼容所有浏览器)
this.$el.find("select[name='updateFrequency']").append("<option value='3'>每隔数小时</option>"));
正确的添加方式:(因为兼容所以浏览器)
this.$el.find("select[name='updateFrequency']")[0].options.add(new Option("每隔数小时","3"));


[b]9,IE浏览器封闭标签[/b]
双日历控件报错,IE7下浏览器左下角有两个字“取消”。
通过关键词搜索,发现是标签封闭错误。


[b]8,content-type在IE浏览器中的错误解析[/b]
在上传文件组件中,后端返回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会当成一段脚本,直接下载了。


[b]7,在Backbone框架的项目中,创建的dialog到底要显示在哪里?[/b]
两种方式:
[b]第一种是在调用的页面里写一个div作为父容器元素。也即是可以嵌套。[/b]
在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传过来,所以是指定的父元素。


[b]第二种是给 el 一个$("<div></div>")作为父容器[/b],情况又分两种
(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里


/*------------------华丽的分割线表明好久没有更新了---------------*/


[b]6,keydown, keyup区别(onpropertychange)[/b]
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可以获取传递的参数


[b]3,this作用域的问题[/b]
$.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())});
});
}
}



[b]2,IE浏览器下实时预览用户在input输入框中输入的数据[/b]
在非IE浏览器下,用input事件
在IE浏览器想,用onpropertychange事件

再加上paste,就完美了。

但是,经查找,onpropertychange属性监听不到的情况:
1,input是disabled时。
2,使用jQuery或其他手段向input设值。

尽管我目前够用了。查到的解决办法只有一个那就是定时监控。
当input获取到焦点时,定时器开启,每隔0.1秒去读input中最新的结果。
一旦input失去焦点,则清除定时器。


[b]1,拼接JSON串耗时较长,完全是试着来的[/b]

//在另一个函数里
_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转成对象,才能使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值