`
zccst
  • 浏览: 3291711 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多
作者:zccst

这些错误不大,却很耽误时间。有时一个很小的问题,耽误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的&lt; &gt;&amp;&quot;&copy;分别是<,>,&,",©;的转义字符
XML只有5个转义符: &lt; &gt;&amp; &quot; &apos;
例如:;;@@。::!!、?'‘’“”"=【】<><>《》~~•,
如果不转义,则会出现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转成对象,才能使用。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics