Javascript Tips - (1)

本文探讨了在浏览器环境中利用JavaScript进行调试的方法,包括console API的使用及注意事项,并详细介绍了如何利用JavaScript制作幻灯片样式的水平移动动画效果,涉及CSS定位及事件监听技巧。

调试工具:


在研究valums-file-uploader的時候,我看到作者用console來作為調試工具:


function(str){
        if (this._options.debug && window.console) console.log('[uploader] ' + str);
}

所以console.log()可以用來輸出變量到控制台,當然是瀏覽器的控制台,但是在我用的瀏覽器中,IE8不支持這個操作,所以前面在使用之前最好加上個if判斷。在Chrome和Firefox里,這是個很好用的東東~~


chrome-console


firefox-console

<12 Mar 2012>


今天在看Firebug的教材的时候,看见Firebug支持的一些调试API,其中console的方法除了log()以外,还有info()warn()error()。之后我就突发奇想,在Chrome里也试了下这些方法,原来Chrome也都支持,我觉得Chrome的设计参考了太多Firefox以及其Adds-On。




用Javascript制作transition effect:


我想不到更好的名称,这个transition effect其实指的是就像幻灯片那样在水平方向上依次移动的效果,在Actionscript里这是个极为简单的效果,因为Cosmos项目的原因,我现在想尝试下在Javascript里制作一个这样的东西。


简单来讲,我需要个这样的东西:


illustrated


容器其实同时也扮演着遮罩的作用,它的目的更主要的还是限定一个区域来给其中的内容呈现用。所以有下面几个功能需要达成:


1. 能够相对于容器的位置来设定其内容元素的位置,并且可以用Javascript来改变此位置;

2. 能够令容器内的内容即使超出了容器的范围,也不会影响容器的大小,并且超出的部分不会被显示,而是被隐藏;


我发现原来搞Javascript并不是说就真的单单只搞Javascript,其实Javascript这个词背后还包括CSS和HTML里的一些琐碎的东西(真是太麻烦了)。相对位置这个东西就是完全靠CSS来控制的,在参阅了《Beginning CSS》


beginning css cover


的第十一章《Positioning》之后,我才得出如下结论:


首先要有一个div标签来做容器,并且它的position属性不可以是static,就我目前试过的有absoluterelative都可以。它的子div的position值需要为absolute。然后通过控制子div的topleftbottomright属性来控制其位置,这四个属性其实指的是上左下右的偏移量,那么就是说:假如我们把一个div元素的左上角当成原点,来建立一个笛卡尔坐标系,那么它的子div元素的left和top这两个属性就可以当成x跟y来用了。


所以我先建立我的HTML文档如下:


<div id="container" style="position: relative; width: 130px; height: 80px; background:pink;">
	<div id="result1" style="position: absolute; background:lightyellow; opacity: 0.7; width: 130px; height: 80px; top:0px; left:0px;">
		<table style="text-align:center">
			<tr>
				<td>Champion1</td>
			</tr>
			<tr>
				<td>Team1 vs Team2</td>
			</tr>
			<tr>
				<td>X : X</td>
			</tr>
		</table>
	</div>
	<div id="result2" style="position: absolute; background:lightblue; opacity: 0.7; width: 130px; height: 80px; top:0px; left:130px;">
		<table style="text-align:center">
			<tr>
				<td>Champion2</td>
			</tr>
			<tr>
				<td>Team3 vs Team4</td>
			</tr>
			<tr>
				<td>X : X</td>
			</tr>
		</table>
	</div>
</div>

首先容器的尺寸是130X80,每个div元素的尺寸也是130X80,在初始状态,把第二个div元素的left设置为130px,这样它就完全在容器遮住范围之外了。那么之后我们就用Javascript的DOM函数来访问这些div并且修改它的.style.left就行了。


下面来看看第二项任务,要想让溢出去的内容不被显示,这个还真的废了我一番周折,最后在这里看到了办法:


http://css-tricks.com/the-css-overflow-property/


其实很简单的,就是设定overflow属性为hidden(默认为visible)。


好,下面到了Javascript的部分了,首先肯定是要先得到这两个div:


var mr_1 = document.getElementById('result1');
var mr_2 = document.getElementById('result2');

然后呢,我需要一个方法,能够将一个元素的left值减小:


function decreaseLeft($element){
	
	try {
		var val = parseInt($element.style.left);
	}
	catch (e){
		console.log($element);
	}
	val = val-5;
	$element.style.left = val + 'px';
}

其实left的值是一个字符串,这里有一个有点儿坑爹的陷阱:

如果你设置一个HTML元素的top,left等属性的值为0,那么它是个有效值,可是如果你设定非零值的时候,就必须要在后面加“px”,不然Chrome会说“invalid value”。


接下来干啥呢,对,需要一个函数来在一定时间内将一个元素从它原来的位置平移到另一个位置:


function slideDivFromToLeft($element, $to)
{
	decreaseLeft($element);
	
	if(parseInt($element.style.left) > $to)
	{
		setTimeout("slideDivToLeft($element, $to)", 100);
	}
}


表面上看这个貌似可以,其实很错误,因为在通过setTimeout()执行的slideDivToLeft()函数里,$element是个无效的引用。那么我们将$element换成一个有效的表达式:


function slideDivFromToLeft($element, $to)
{
	decreaseLeft($element);
	
	if(parseInt($element.style.left) > $to)
	{
		setTimeout("slideDivFromToLeft(" + $element + "," + $to + ")", 100);
	}
}

这样做其实也是错的,于是我去google,得到:


http://bytes.com/topic/javascript/answers/759300-setinterval-parameters


修改成:


function slideDivFromToLeft($element, $to)
{
	decreaseLeft($element);
	
	if(parseInt($element.style.left) > $to)
	{
		setTimeout("slideDivFromToLeft('" + $element + "'," + $to + ")", 100);
	}
}

还是不行,另外,请注意,其实对于数值类型的参数,不需要加引号,因为加了之后会变成字符串来处理,然后Javascript就又得做一次隐式类型转换。


最后找到关于setTimeout()setInterval()函数在指定一个函数时如何传递参数:


http://stackoverflow.com/questions/457826/pass-parameters-in-setinterval-function

http://www.makemineatriple.com/2007/10/passing-parameters-to-a-function-called-with-settimeout


所以,正确的写法是:


function slideDivFromToLeft($element, $to)
{
	decreaseLeft($element);
	
	if(parseInt($element.style.left) > $to)
	{
		setTimeout( function() { slideDivFromToLeft($element, $to); }, 100);
	}
}

但是仍然没有完美,这样通过使用匿名函数的坏处是,每一次执行该函数都会导致一个函数对象被创建。所以这个做法有导致内存泄露的嫌疑,当然具体的效果完全有赖于浏览器的垃圾回收机制。


最后的完整代码:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<title>Vincent's Test: Sliding Tables</title>
	</head>
	<body>
		<div id="container" style="position: relative; width: 130px; height: 80px; background:pink; overflow: hidden;">
			<div id="result1" style="position: absolute; background:lightyellow; opacity: 0.7; width: 130px; height: 80px; top:0px; left:0px;">
				<table style="text-align:center">
					<tr>
						<td>Champion1</td>
					</tr>
					<tr>
						<td>Team1 vs Team2</td>
					</tr>
					<tr>
						<td>X : X</td>
					</tr>
				</table>
			</div>
			<div id="result2" style="position: absolute; background:lightblue; opacity: 0.7; width: 130px; height: 80px; top:0px; left:130px;">
				<table style="text-align:center">
					<tr>
						<td>Champion2</td>
					</tr>
					<tr>
						<td>Team3 vs Team4</td>
					</tr>
					<tr>
						<td>X : X</td>
					</tr>
				</table>
			</div>
		</div>
		<script type="text/javascript">
		
			var mr_1 = document.getElementById('result1');
			var mr_2 = document.getElementById('result2');
			
			function slideDivFromToLeft($element, $to)
			{
				decreaseLeft($element);
				
				if(parseInt($element.style.left) > $to)
				{
					setTimeout( function() { slideDivFromToLeft($element, $to); }, 100);
				}
			}
			
			function decreaseLeft($element){
				
				try {
					var val = parseInt($element.style.left);
				}
				catch (e){
					console.log($element);
				}
				val = val-5;
				$element.style.left = val + 'px';
			}
			
			slideDivFromToLeft(mr_2, 0);
			slideDivFromToLeft(mr_1, -130);
			
		</script>
	</body>
</html>

在Chrome,IE8还有Firefox以及我的AIR-HTMLLoader测试都OK。

sliding


不同浏览器对于DOM中TEXT节点的解析:


今天发现这样一个问题,假如你有一个DIV标签,你原本的意思是只用它来做一个容器,即在HTML页面里它是空的,它里面的内容完全是由你的Javascript来动态加入,同时假设你只需要它每次只含有一个子标签,于是你可能会自然而然地想通过XML DOM标准里定义的replaceChild()函数来实现。


下面就是问题了,如果你的DIV标签是这样写的:


<div id="result1" style="position: static; background:lightyellow; width: 130px; height: 80px; z-index:1">

</div>

然后你通过这句来实现你的替换:


var mr_1 = document.getElementById('result1');
mr_1.replaceChild(mreutsArray[currentIndex], mr_1.childNodes[0]);



那么,你将会发现这个写法只有在IE里是正常,在Chrome与Firefox还有AIR-HTMLLoader里却得出很奇怪的结果:在某些时刻,这个DIV标签会同时显示出两个table元素。


在Chrome、FirefoxAIR-HTMLLoader里如果换成这样的写法:

var mr_1 = document.getElementById('result1');
mr_1.replaceChild(mreutsArray[currentIndex], mr_1.childNodes[1]);


才会正常。为什么呢?


通过调试,我发现,原来在Chrome、FirefoxAIR-HTMLLoader里,一个标签内的任何字符都会导致它在生成DOM树时被分析成一个TEXT节点,即使这个字符串仅包含空格换行符和制表符,所以这就导致在加载完HTML生成DOM树时,DIV已经有了一个子节点了,它是内容仅为一个换行符的TEXT节点,之后你再插入一个table到它的子节点列表里,于是它就有了两个,而mr_1.childNodes[0]将会引用到的是那个空的文本节点,所以将它替换将导致DIV同时拥有两个table。而IE并不会为换行符生成一个文本节点插入DOM树里,所以上面的写法在IE下就会正常运行。


结论就是,兼容几个浏览器的通用写法是,不要在标签里加入任何符号:


<div id="result1" style="position: static; background:lightyellow; width: 130px; height: 80px; z-index:1"></div>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值