JavaScript:CSS动画函数

/**
* AnimateCSS.js
* This file defines a function named animateCSS(), which serves as a framework
* for creating CSS-based animations, The arguments to this function are:
*
* 	element: The HTML element to be animated.
* 	numFrames: The total number of frames in the animation.
* 	timePerFrame: The number of milliseconds to display each frame.
* 	animation: An object that defines the animationl described below.
* 	whendone: An opional function to call when the animation finishes.
* 			  If specified, this function is passed element as ites argument.
*
* The animateCSS() function simply defines an animation framework. It is
* the properties of the animation object that specify the  animation to be
* done. Each property should have the same name as a CSS style property. The
* value of each property must be a function that returns values for that
* style property. Each function is passed the frame number and the total
* amount of elapsed time, and it can use these to compute the style value it
* should return for that frame. For example, to animate an image so that it
* slides in from the upper left. you might invoke animateCSS as follows:
*
* 	animateCSS(images, 25, 50,	// Animate image for 25 frames of 50ms each
*			  {	// Set up and left attributes for each frame as follows:
*				top: function(frame, time){ return frame*8 + "px";},
*				left: function(frame, time){ return frame*8 + "px";}
*	});
*
*/
function animateCSS(element, numFrames, timePerFrame, animation, whendone) {
	var frame = 0;	// Store current frame number
	var time = 0;	// Store total elapsed time

	// Arrange to call displayNextFrame() every timePerFrame milliseconds.
	// This will display each of the frames of the animation.
	var intervalId = setInterval(displayNextFrame, timePerFrame);

	// The call to animateCSS() returns now, but the previous line ensures that
	// the following nested function will be invoked once for each frame
	// of the animation.
	function displayNextFrame() {
		if(frame >= numFrames) {				// First, see if we're done
			clearInterval(intervalId);			// If so, stop calling ourselves
			if(whendone) whendone(element);		// Invoke whendone function
				return;							// And we're finished
		}

		// Now loop through all properties defined in the animation object
		for(var cssprop in animation) {
			// For each property, call its animation function, passing the
			// frame number and the elapsed time, Use the return value of the
			// function as the new value of the corresponding style property
			// exceptions caused by bad return values.
			try{
				element.style[cssprop] = animation[cssprop] (frame, time);
			}catch(e) {}
		}

		frame++;				// Increment the frame number
		time += timePerFrame;	// Increment the elapsed time
	}
}

我们这样使用它们

<script type="text/javascript" src="AnimateCSS.js" ></script>
<style type="text/css">
#button{position: absolute;}
</style>
<input type="button" value="button" id="button"/>
<div id="title"></div>
<script type="text/javascript">
	var button = document.getElementById("button");
	animateCSS(button, 40, 50,
		{
			left: function(f, t) { return 200 + 100*Math.cos(f/8) +  "px"},
			top: function(f, t){ return 200 + 100*Math.sin(f/8) + "px"}
		},
		function(button){
			button.value = "Done";
		}
	);
</script>

Demo:http://fakefish.sinaapp.com/demo/animatecss.html

JavaScript:可移植的查询窗口几何属性的方法

/**
* Geometry.js:portable functions for querying window and document geometry
*
* This module defines functions for querying window and document geometry.
*
* getWindowX/Y():return the position of the window on the screen
* getViewportWidth/Height():return the size of the browser viewport area
* getDocumentWidth/Height():return the size of the document
* getHorizontalScroll():return the position of the horizontal scrollbar
* getVerticalScroll():return the positon of the vertical scrollbar
*
* Note that there is no portable way to query the overall size of the browser window, so there are no getWindowW/Height() functions.
*
* IMPORTANT:This module must be included in the <body> of a document instead of the <head> of the document.
*
*/
var Geometry = {};
if(window.screenLeft){ //IE and others
	Geometry.getWindowX = function(){ return window.screenLeft;};
	Geometry.getWindowY = function(){ return window.screenTop;};
}
else if(window.screenX){ //Firefox and others
	Geometry.getWindowX = function(){ return window.screenX;};
	Geometry.getWindowY = function(){ return window.screenY;};
}

if(window.innerWidth){ //All browsers but IE
	Geometry.getViewportWidth = function(){ return window.innerWidth;};
	Geometry.getViewportHeight = function(){ return window.innerHeight;};
	Geometry.getHorizontalScroll = function(){ return window.pageXOffset;};
	Geometry.getVerticalScroll = function(){ return window.pageYOffset;};
}
else if (document.documentElement && document.documentElement.clientWidth){
	//These functions are for IE6 when there is a DOCTYPE
	Geometry.getViewportWidth = function(){ return document.documentElement.clientWidth;};
	Geometry.getViewportHeight = function(){ return document.documentElement.clientHeight;};
	Geometry.getHorizontalScroll = function(){ return document.documentElement.scrollLeft;};
	Geometry.getVerticalScroll = function(){ return document.documentElement.scrollTop;};
}
else if (document.body.clientWidth){
	//These are for IE4,,IE5,and IE6 without a DOCTYPE
	Geometry.getViewportWidth=function(){ return document.body.clientWidth;};
	Geometry.getViewportHeight=function(){ return document.body.clientHeight;};
	Geometry.getHorizontalScroll=function(){ return document.body.scrollLeft;};
	Geometry.getVerticalScrill=function(){ return document.body.scrollTop;};
}

//There functions return the size of the document. They are not window
//related,but they are useful to have here anyway.
if(document.documentElement && document.documentElement.scrollWidth){
	Geometry.getDocumentWidth = function(){ return document.documentElement.scrollWidth;};
	Geometry.getDocumentHeight = function(){ return document.documentElement.scrollHeight;};
}
else if(document.body.scrollWidth){
	Geometry.getDocumentWidth = function(){ return document.body.scrollWidth;};
	Geometry.getDocumentHeight = function(){ return document.body.scrollHeight;};
}

JavaScript实现字体阴影

虽说CSS3自带字体阴影,但低版本游览器不显示。看到犀牛书上正好有这方面的例子。学习了。

/**
* Shadows.js: Shadows text with css.
*
* This module defines a single global object named Shadows.
* The properties of this object are two utility functions.
*
* Shadows.add(element, shadows):
* 	Add the specified shadows or element to the specified element. The first argument
* 	is a document element or element id . This element must hava a single
* 	test node as its child. This child is the one that will be shadowed.
* 	Shadows are specified with a string argument whoes syntax is explained
* 	below.
*
* Shadows.addAll(root, tagname):
* 	Find all descendants of the specified root element that have the
* 	specified tagname. If any of these elments have and the value if its
* 	shadow, then call Shadows.add() for the element and the value of its
* 	shadow attribute, If tagname is not specifiedm, all elements are checked.
* 	If root is not specified, the document object is used. This function is
* 	intended to be called once, when a document is first loaded.
*
* Shadow Syntax
* Shadows are specified by a string of the form [x y color]+. That is, one
* or more triplets specifying an x offset, a y offset, and a color, Each of
* these values must be in legal CSS format, If more than one shadow is
* specified, then the first shadow specified is on the bottom, overlapped
* by subsequent shadows. For example: "4px 4px #ccc 2px 2px #aaa"
*/
var Shadows = {};
//Add shadows to a single specified element
Shadows.add = function (element, shadows) {
	if (typeof element == "string")
		element = document.getElementById(element);
	// Break the shadows string up at whitespace, first stripping off
	// any leading and trailing spaces.
	shadows = shadows.replace(/^\s+/, "").replace(/\s+$/, "");
	var args = shadows.split(/\s+/);
	// Find the text node that we are going to shadow.
	// This module would be more robust if we shadowed all children.
	// For simplicity, though, we're only going to do one.
	var textnode = element.firstChild;
	// Give the container elment relative positioning, so that
	// Shadows can be positioned relative to it.
	// We'll learn about scripting the style property in this way later.
	element.style.position = "relative";
	//Create the shadows
	var numshadows = args.length/3;			//how many shadows?
	for(var i = 0;i < numshadows; i++){		//for each one
		var shadowX = args[i*3];			//get the X offset
		var shadowY = args[i*3 + 1];		//the Y offset
		var shadowColor = args[i*3 + 2];	//and the color arguments
		//Create a new <span> to hold the shadow
		var shadow = document.createElement("span");
		//Use its style attribute to specify offsetand color
		shadow.setAttribute("style", "position:absolute; " +
							"left:" + shadowX + ";" +
							"top:" + shadowY + ";" +
							"color:" + shadowColor + ";");
		// Add a copy of the text node to this shadow span
		shadow.appendChild(textnode.cloneNode(false));
		// And add the span to the container
		element.appendChild(shadow);
	}
	//Now we put the text on top of the shadow. First, create a <span>
	var text = document.createElement("span");
	text.setAttribute("style", "position:relative");//postion it
	text.appendChild(textnode);
	element.appendChild(text);
};
	// Scan the document tree at and beneath the specified root element for
	// elements with the specified tagname. If any have a shadow attribute,
	// pass it to the Shadow.add() method above to create the Shadow.
	// if root is omitted, use the document object. If tagname is omitted,
	// search all tags.
	Shadows.addAll = function(root, tagname) {
		if(!root)							//Use whole document if no root
			root = document;
		if(!tagname)						//Use any tag if no tagname specified
			tagname = '*';
		var elements = root.getElementsByTagName(tagname);		//Find all tags
		for(var i = 0; i < elements.length; i++){				//For each tag
			var shadow = elements[i].getAttribute("shadow");	//If it has a shadow
			if(shadow)
				Shadows.add(elements[i], shadow);				//create the shadow
		}
	};

我们这样使用它:

<body onload="Shadows.addAll();">
<div style="font:bold 32pt sans-serif;">
	<span shadow='5px 5px #ccc 3px 3px #888 1px 1px #444'>Shadow</span>
</div>
</body>

在JavaScript中模拟类–复数

/*
* Complex.js:
* This file defines a Complex class to represent complex numbers.
* Recall that a complex number is the sum of a real number and and
* imaginary number and that the imaginary number i is the
* square root of -1.
*
*/
/*
* The first step in defining a class is defining the constructor
* function of the class. This constructor should initialize any
* instance properties of the object. These are the essential
* "state variables" that make each instance of the class diffent.
*/
function Complex(real, imaginary){
	this.x = real;
	this.y = imaginary;
}
/*
* The second step in defining a class is defining its instance
* methods (and possibly other properties) in the prototype object
* of the constructor. Any properties defined in this object will
* be inherited by all instances of the class. Note that instance
* methods operate on the this keyword. For many methods,
* no other arguments are needed.
*/
//Return the magnitude of a complex number. This is defined
//as its distance from the origin (0,0) of the complex plane
Complex.prototype.magnitude = function() {
	return Math.sqrt(this.x*this.x + this.y*this*y);
};
//Return a complex number that is the negative of this one.
Complex.prototype.negative = function() {
	return new Complex(-this.x,-this.y);
};
//Add a complex number to this one and return the sum in a new object.
Complex.prototype.add = function(that) {
	return new Complex(this.x + that.x, this.y + that.y);
};
//Multiply this complex number by anther and return the product as a
//new Complex object.
Complex.prototype.multiply = function(that) {
	return new Complex(this.x * that.x - this.y * that.y, this.x * that.y + this.y * that.x);
};
//Convert a Complex object to a string in a useful way.
//This is invoked when a Complex object is used as a string.
Complex.prototype.toString = function() {
	return "{" + this.x + "," + this.y +"}";
};
//Test whether this Complex object has the same value as another.
Complex.prototype.equals = function(that) {
	return this.x == that.x && this.y == that.y;
};
//Return the real portion of a complex number. This function
//is invoked when a Complex object is treated as a primitive value
Complex.prototype.valueOf = function() {
	return this.x;
};
/*
* The third step in defining a class is to define class methods,
* constants, and any needed class properties as properties of the
* constructor function itself (instead of as properties of properties of the
* prototype object of the constructor).Note that class methods
* do not use this keyword: they operate only on their arguments.
*/
Complex.sum = function(a,b) {
	return new Complex(a.x + b.x, a.y + b.y);
};
Complex.product = function(a,b) {
	return new Complex(a.x * b.x - a.y * b.y, a.x * b.x + a.y * b.y);
};
// Here are some useful predefined complex numbers
// They are defined as class properties, and their names are in uppercase
// to indicate that they are instended to be constants (although it is not
// possible to make JavaScript properties read-only).
Complex.ZERO = new Complex(0,0);
Complex.ONE = new Complex(1,0);
Complex.I = new Complex(0,1);
var a = new Complex(1,1);
var b = new Complex(1,2);
console.log(Complex.sum(a,b));//return Complex(2,3)
console.log(a.equals(b));//return false

JavaScript:让表格更灵活–表格排序

用于对表格的排序。

(忽略HTML吧)

function TableSort(id){
 this.tbl = document.getElementById(id);
 this.lastSortedTh = null;
 if(this.tbl && this.tbl.nodeName == "TABLE"){//判断是否存在且为表格
 var headings = this.tbl.tHead.rows[0].cells;//获取表头成员
 for(var i=0;headings[i];i++){
 if(headings[i].className.match(/asc|dsc/)){//
 this.lastSortedTh = headings[i];
 }
 }
 this.makeSortable();//让他排序
 }
}
TableSort.prototype.makeSortable = function(){
 var headings = this.tbl.tHead.rows[0].cells;//获取表头成员数组
 for(var i=0;headings[i];i++){
 headings[i].cIdx = i;//解决Safari2.0.4的bug导致对cellIndex的返回值永远为0
 //接下来为每个th元素外包一个a,让用户可以通过tab键激活表头,回车触发onclick事件
 var a = document.createElement("a");
 a.href = "#";
 a.innerHTML = headings[i].innerHTML;
 a.onclick = function(that){
 return function(){
 that.sortCol(this);
 return false;
 }
 }(this);//使用闭包指向TableSort实例
 headings[i].innerHTML = "";
 headings[i].appendChild(a);
 }
}
TableSort.prototype.sortCol = function(el){
 var rows = this.tbl.rows;//所有行
 var alpha = [],numeric = [];//该列所有格子的文字型内容和数值型内容分开存放于这两个数组中
 var aIdx = 0,nIdx = 0;//用于索引上面两个数组
 var th = el.parentNode;//这是被点击钩子的父节点引用,即th.钩子的引用是el,作为函数的参数传进来
 var cellIndex = th.cIdx;//这个变量存放th元素在其所在行的索引。通过它,可以直接跳到当前列在每行对应的格子,从而高效地遍历一列的所有格子
 for(var i=1;rows[i];i++){
 var cell = rows[i].cells[cellIndex];
 var content = cell.textContent ? cell.textContent : cell.innerText;//FF只支持textContent,IE只支持innerText
 var num = content.replace(/(\$|\,|\s)/g, "");//去除美元,逗号和空格等
 if(parseFloat(num) == num){//判断省下的是否是数值
 numeric[nIdx++] = {
 value:Number(num),
 row:rows[i]
 }
 }else{
 alpha[aIdx++] = {
 value:content,
 row:rows[i]
 }
 }
 }
//按方向进行排序
 var col = [],top,bottom;
 if(th.className.match("asc")){
 top = bubbleSort(alpha,-1);
 bottom = bubbleSort(numeric,-1);
 th.className = th.className.replace(/asc/,"dsc");
 }else{
 top = bubbleSort(numeric,1);
 bottom = bubbleSort(alpha,1);
 if(th.className.match("dsc")){
 th.className = th.className.replace(/dsc/,"asc");
 }else{
 th.className +="asc";
 }
 }
 //如果最近一次排序的表格列的th和被点击的不一样,就清楚他的asc/dsc类名
 if(this.lastSortedTh && th != this.lastSortedTh){
 this.lastSortedTh.className = this.lastSortedTh.className.replace(/dsc|asc/g,"");
 }
 this.lastSortedTh = th;
 col = top.concat(bottom);
 var tBody = this.tbl.tBodies[0];
 for(var i=0;col[i];i++){
 tBody.appendChild(col[i].row)
 }
}
function bubbleSort(arr,dir){
 var start,end;
 if(dir === 1){//dir的两个值,1和-1,分别代表升序和降序
 start = 0;
 end = arr.length;
 }else if(dir === -1){
 start = arr.length-1;
 end = -1;
 }
 var unsorted = true;
 while(unsorted){//冒泡排序
 unsorted = false;
 for(var i=start;i!=end;i=i+dir){
 if(arr[i+dir] && arr[i].value > arr[i+dir].value){
 var a = arr[i];
 var b = arr[i+dir];
 var c = a;
 arr[i] = b;
 arr[i+dir] = c;
 unsorted = true;
 }
 }
 }
 return arr;
}

就不详细说了,注释都写了

感想是对闭包的概念还不是很了解QAQ

demo地址:http://fakefish.me/test/js/tablesort.html

来自The Art & Science Of Javascript

官方地址:http://www.sitepoint.com/books/jsdesign1/