1、关于scrollTop 的问题
只有在容器处于显示状态时,重设scrollTop才会生效。否则将无效。
2、关于cookie路径的问题
存储cookie时需要注意路径的问题。即使用jquery.cookie插件时,一定要注意第三个参数的设置。
3、关于IE6之Fixed定位问题
众所周产于公元2002年、且当前为我国主流的IE6浏览器是不支持CSS2的静止定位属性fixed,蛋疼的前端工程师们为此发明了各种形式的解决方案:
一、常规js解决之道
这个方案最为古老,比IE6还老,且应用十分广泛:比如很多跟着滚动条走的对联广告就是使用此方案。缺点就是拖动滚动条元素抖动很厉害,虽然通过平滑处理可以改善下,效果仍然不理想。不过要说的是此方案虽然视觉效果差了那么一点,稳定性与可控性没得二话说的。
二、动用HTML结构与布局模拟法
此方案曾经被163博客应用,163把所有的内容放在一个高度100%且滚动条设置为自动的容器中,然后再下面设置一个绝对定位的层,这样这个绝对定位的层就可以达到静止状态。原理:你拖动的滚动条并不是拖动的整个页面,而是那个模拟整页的容器,所以容器外的地方都是“静止”的。详细:http://bbs.blueidea.com/thread-2930592-1-1.html
这里视觉效果达到完美,问题有三:
1、需要改变HTML结构
2、破坏了用户体验:刷新页面之后滚动条不会停留在原处
3、破坏js一些事件,如cwindow的scroll事件
三、、老技术新用的expression加fixed背景方案
此方案能够视觉上完美的实现静止定位。例子:
cloudgamer:AlertBox 弹出层(信息提示框)效果
这两种方案本来已经很完美了,我artDialog早期版本也是这么实现的,可是后来使用过程中发现了一个更加不能容忍的BUG,我在回复cloudgamer写了BUG触发DEMO。
这个问题的本质就是用expression模拟fixed外包裹元素实际是设置了absolute,并且遮盖了页面,IE6可能导致其下页面一些元素无法响应事件,如div、td、span等,只有a、button、input等元素可以响应,那些无法响应事件的元素如果包含了文字BUG又会消失。
下面的DEOM代码是我四天前写好的,直到今天才在自己Blog上分享,希望彻底埋了第上述第四方案的坑了:
<!DOCTYPE>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ie6 Fixed</title>
</head>
<body>
<p><button id="fixedBtn">设置静止定位</button><button id="fixedBtn2">改变位置</button></P>
<P><button id="absoluteBtn">设置绝对定位</button><button id="absoluteBtn2">改变位置</button></P>
<div id="fixed" style="width: 60px; height:60px; background:#C0C0C0; border:solid 1px #000;"></div>
<div style="height:1400px;" title="请拖动滚动条"></div>
<script type="text/javascript">
var position = function(){
var isIE6 = !-[1,] && !window.XMLHttpRequest,
html = document.getElementsByTagName('html')[0],
dd = document.documentElement,
db = document.body,
dom = dd || db,
// 获取滚动条位置
getScroll = function(win){
return {
left: Math.max(dd.scrollLeft, db.scrollLeft),
top: Math.max(dd.scrollTop, db.scrollTop)
};
};
// 给IE6 fixed 提供一个"不抖动的环境"
// 只需要 html 与 body 标签其一使用背景静止定位即可让IE6下滚动条拖动元素也不会抖动
// 注意:IE6如果 body 已经设置了背景图像静止定位后还给 html 标签设置会让 body 设置的背景静止(fixed)失效
if (isIE6 && document.body.currentStyle.backgroundAttachment !== 'fixed') {
html.style.backgroundImage = 'url(about:blank)';
html.style.backgroundAttachment = 'fixed';
};
return {
fixed: isIE6 ? function(elem){
var style = elem.style,
doc = getScroll(),
dom = '(document.documentElement || document.body)',
left = parseInt(style.left) - doc.left,
top = parseInt(style.top) - doc.top;
this.absolute(elem);
style.setExpression('left', 'eval(' + dom + '.scrollLeft + ' + left + ') + "px"');
style.setExpression('top', 'eval(' + dom + '.scrollTop + ' + top + ') + "px"');
} : function(elem){
elem.style.position = 'fixed';
},
absolute: isIE6 ? function(elem){
var style = elem.style;
style.position = 'absolute';
style.removeExpression('left');
style.removeExpression('top');
} : function(elem){
elem.style.position = 'absolute';
}
};
}();
</script>
<script>
var elem = document.getElementById('fixed');
document.getElementById('fixedBtn').onclick = function(){
elem.style.left = '100px';
elem.style.top = '100px';
position.fixed(elem);
};
document.getElementById('fixedBtn2').onclick = function(){
elem.style.left = '400px';
elem.style.top = '100px';
position.fixed(elem);
};
document.getElementById('absoluteBtn').onclick = function(){
elem.style.left = '100px';
elem.style.top = '100px';
position.absolute(elem);
};
document.getElementById('absoluteBtn2').onclick = function(){
elem.style.left = '400px';
elem.style.top = '100px';
position.absolute(elem);
};
</script>
</body>
</html>
四、使用js 设置 expression 与 removeExpression 法
在实现了ie6 fixed的前提下,实际应用中可能还需要对这个fixed元素调整位置,如鼠标拖拽元素。上面的DEMO同样是使用expression实现,不同的是expression直接应用到了要操作的对象上,这样就不会发生上述BUG了,直接设置在元素上后再想手动改变元素位置(如拖动)是相当困难的,必须有一个可以重置expression的方法,而前些天在msdn上看到的removeExpression方法,问题迎刃而解!你也可以看artDialog3在IE6 fixed的表现。
如果光说到标准的fixed定位除了left与top之外还有right与bottom属性,显然目前此方案支持它们会比较麻烦,还好就是这两个属性在javascript组件中很少用到。
4、关于循环中闭包的问题
在项目中经常遇到for循环中返回函数的问题,每次用的方法很杂,总结一下~
问题引入:
var li=document.getElementsByTagName("li");
for(var i=0;i<li.length;i++){
li[i].onclick=function(){alert(i);}
}
闭包允许你引用父函数中的变量,但提供的值并非该变量创建时的值,而是在父元素范围内的最终值。
解决方案一: 用一个匿名函数包含语句块,同时传入一个参数后执行,传如参数就成了局部变量。
for(var i=0;i<li.length;i++){
(function(index){
li[index].onclick=function(){
alert(index);
}
})(i);
}
解决方案二: 通过dom元素绑定属性来记录下标。
for(var i = 0,len = lists.length;i < len;i++){
lists[i].j = i;//通过dom的属性绑上j属性,即是i的索引,从而j就记录下了j
lists[i].onclick=function(){
alert(this.j); //直接访问其dom属性
};
}
解决方案三:调用匿名函数自身的保存的i属性的变量。
var lists = document.getElementsByTagName("li");
for(var i = 0,len = lists.length;i < len;i++){
(lists[i].onclick =function(){
alert(arguments.callee.i);//匿名函数调用自身的属性的i
}).i=i;
}
解决方案四:再加一层闭包,返回一个函数作为响应事件。
for(var i = 0,len = lists.length;i < len;i++){
lists[i].onclick = (function(j){
return function(){//响应事件的函数,参数i作为j,这样i就成了响应事件的局部变量
alert(j);
}
})(i);
}
}
5、关于with的两个困惑
’use strict‘ 模式下,with直接被禁用!
【with】:(对象闭包),所谓对象闭包是指使用with语句时与with()所指示对象相关的闭包,该闭包被动态创建并添加到执行环境当前的闭包链顶端。-----摘自《javascript语言精髓与编程实践》4.6.4.2
【愚见】:with的好处是可以很方便的增删改对象中的属性。问题是,遇到变量冲突和双重闭包就悲剧了。至于网上各位大牛所说的性能问题,我...真心表示不懂。
【示例】:
实例一:
根据周老师书中所言,大意是,因为abc()的函数闭包位于obj的对象闭包中,因此abc()中方位value时应该通过闭包链来存取到obj.value。但事实上,abc()函数的闭包链早在语法分析器就决定了,它被添加在全局闭包之后。因此,abc()的函数闭包与obj的对象闭包并列,obj对象闭包中将无法获取obj.value的值。更无法改变它。
预期打印结果:
obj.value: 100
value: 2000
实例二:
为解决实例一无法获取对象中value值的问题,将代码进行修改,即实例二所示代码。将对象闭包中的函数闭包改为匿名函数。这样可以修改对象obj1.value1,而不会修改value1。
预期打印结果:
obj.value: 100
value: 2000
// 实例一
var obj = {value : 100};
var value = 1000;
with(obj){
function abc(){
value *= 2;
}
abc();
}
console.info('obj.value: ' + obj.value);
console.info('value: ' + value);
console.info("---------------------------------------");
//实例二
var obj1 = {value : 100};
var value1 = 1000;
with(obj1){
void function(){
value1 *= 2;
}();
}
console.info('obj1.value: ' + obj1.value);
console.info('value1: ' + value);
最后测试结果:
safari与chrome同核,结果一样,就不贴了。三个浏览器都是到现在这个时间为止的最新版本,不想截版本信息没有意义。不过ie10能支持console.info,真让我感动的痛哭流涕。
实例三:
var obj = new Object();
obj.value = 100;
console.info("befor changed:");
console.info(obj);
console.info(obj.value);
with(obj){
value += 100;
}
console.info("after changed:");
console.info(obj);
console.info(obj.value);
最后测试结果:(浏览器同上一样)
这里最让我不解的是,三个浏览器对object.value改变前后的输出结果,都是一样。但是,在chrome中,with物理位置之前,直接输出object对象时,它里面的属性value值是改变之后的值。看图可以很明显看出。但是,在中间的ff中,就不一样了。很费解。ie10没法直接打印出对象内部属性,不知道详情。
但是ff和chrome的差异让我很不理解。不清楚这个程序到底是怎么执行的。
chrome中。按我的理解是,因为对象本身就是一个引用,所以,输出对象时,里面的值自然是最终改变后的值,这跟输出的物理位置是无关的。而object.value就是一个具体的值了,它受到代码运行物理位置的影响,所以看起来就跟object不同步了。但是,ff中的现象又改怎么理解呢?
PS:刚才把ff升级到最新5.0版本,然后发现下面截图所示内容。
(点击红色框框,进入到对象中)
结语:那就是说,我的理解没有错,只是ff在打印的时候,记录了一个object的临时状态,但是如果展开object对象,它显示的将是被引用值的最后状态。
6、不同浏览器和设备加载本地xml文件问题
在本地测试时,IE各版本,safari,ff都能使用jquery的ajax来进行加载,但是在chrome中不行。在chrome中只能用ip地址来访问才能对xml进行正常加载,即必须将网页放到服务器上,用ip才能看到加载后的效果。可将文件放到本地虚拟服务器中,用localhost来访问调试。
7、 this 的指向问题
注册事件,当事件被触发之后,函数或方法中的this指向已经发生改变,所指为事件触发的对象。这个其实是常识,不过容易忽略,给调试造成麻烦。因此,只要是函数中需要进行事件注册,那么,在事件注册之前,最好先创建一个局部变量,把this赋给该局部变量。然后在事件的callback中需要引用this的地方,引用该局部变量。(切记切记!)
在事件的callback中运行某方法时,必须使用call或apply,将scope传递进去!(详见南商main.js)
在提示方法未定义式时,首先最好是直接在引用该方法的代码前一行对this进行console.info(this)。
8、关于 console.info(); 语句前后的注释问题
写在 console.info(); 语句之前或之后的注释,会直接打印在浏览器中
9、关于匿名函数的书写问题
以下几种书写格式都正确:
Void操作符:用void操作符去执行一个没有用圆括号包围的一个单独操作数。
void function(){}()
函数字面量:首先声明一个函数对象,然后执行它。
(function(){})() 如果漏掉最外层的括号,将提示语法错误!
var a = function(){}() (⊙o⊙)…这个算隐形匿名了,哈哈
优先表达式:由于Javascript执行表达式是从圆括号里面到外面,所以可以用圆括号强制执行声明的函数。
(function(){}())