Google在韩国的主页非常漂亮,抓图如下:
之所以提到这个页面是因为在这个页面中实现动画效果的方式非常有趣,也告诉我们JavaScript可以用到这种境界。你可以查看Google的源代码,可惜这些代码经过了混淆器的处理不是很容易读。不过这里有对Google代码的简化版。
单击查看运行效果,相关代码如下:
var Binding = function (func, owner) {
var args = func.args || [];
args = args.concat(Array["prototype"]["slice"].call(arguments, 2));
if (func.owner) {
owner = func.owner;
}
if (func.code) {
func = func.code;
}
var cacheFunc = function () {
var tempArgs = args.concat(Array["prototype"]["slice"].call(arguments));
return func.apply(owner, tempArgs);
};
cacheFunc.args = args;
cacheFunc.owner = owner;
cacheFunc.code = func;
return cacheFunc;
};
Function["prototype"].bind = function (owner) {
return Binding.apply(null, [this, owner].concat(Array["prototype"]["slice"].call(arguments, 1)));
};
Function["prototype"].inherits = function (baseClass) {
function inheritance() {
}
inheritance.prototype = baseClass["prototype"];
this.prototype = new inheritance();
this["prototype"].constructor = this;
this.superClass = baseClass.prototype;
};
var Event = function (event) {
this.type = event["type"];
this.target = event["target"] || event.srcElement;
this.currentTarget = event["currentTarget"] || event.srcElement;//there is something wrong now
//eventPhase
//bubbles
//cancelable
this.timeStamp = new Date();
//only for mouse event
this.relatedTarget = null;
if (typeof event["relatedTarget"] != "undefined") {
this.relatedTarget = event["relatedTarget"];
} else {
if (this["type"] == "mouseover") {
this.relatedTarget = event.fromElement;
} else {
if (this["type"] == "mouseout") {
this.relatedTarget = event.toElement;
}
}
}
this.event = event;
};
var Listener = function (obj) {
this.obj = obj;
};
Listener["prototype"].listen = function (element, eventName, func) {
var owner = this.obj;
if (element.addEventListener) {
element.addEventListener(eventName, function(event){func.call(owner,new Event(event));}, false);
} else {
if (element.attachEvent) {
element.attachEvent("on" + eventName, function(){func.call(owner,new Event(window.event));});
} else {
throw Error("Object {" + element + "} does not
support event listeners.");
}
}
};
Listener["prototype"].unlisten = function (element, eventName, func) {
};
Listener["prototype"].handleEvent = function () {
};
var Animation = function (element, frames, ySpritePosition, animationSpeed, mouseoutTime,textId) {
Listener.call(this,this);
this.el = element;
this.mouseTimeout = null;
this.mouseTimeoutTime = mouseoutTime;
this.frames = frames - 1;
this.ySpritePosition = ySpritePosition;
this.animationSpeed = animationSpeed;
this.animationSpeedTimeout = null;
this.panelElement = this.el.getElementsByTagName("span")[0];
this.frameWidth = this.panelElement["offsetWidth"];
this.flyTip = textId ? new FlyTip(this, textId) : undefined;
this.step = -1;
this.currentFrame = 1;
this.listen(this.el, "mouseover", this.start);
this.listen(this.el, "mouseout", this.stop);
this.listen(document, "mouseout", this.quit);
};
Animation.inherits(Listener);
Animation["prototype"].play = function (step, playFrame) {
if (step !== undefined) {
this.step = step;
this.mouseTimeout = window.clearTimeout(this.mouseTimeout);
this.animationSpeedTimeout = window.clearTimeout(this.animationSpeedTimeout);
}
if (playFrame !== undefined) {
this.currentFrame = playFrame;
}
var position = "-" + this.frameWidth * this.currentFrame + "px " + this.ySpritePosition;
this.panelElement["style"].backgroundPosition = position;
if (this.step == 1 && this.currentFrame >= this.frames) {
this.currentFrame = this.frames - 1;
return;
} else {
if (this.step == -1 && this.currentFrame <= 0) {
this.currentFrame = 1;
return;
} else {
if (this.flyTip && this.step == 1 && !this.flyTip.isShowing) {
this.flyTip.show();
} else {
if (this.flyTip && this.step == -1 && this.flyTip.isShowing) {
this.flyTip.hide();
}
}
}
}
this.animationSpeedTimeout = window.setTimeout(this["play"].bind(this, undefined, this.currentFrame += this.step), this.animationSpeed);
};
Animation["prototype"].start = function (event) {
this.mouseTimeout = window.clearTimeout(this.mouseTimeout);
if (this.step == -1) {
this.mouseTimeout = window.setTimeout(this["play"].bind(this, 1, undefined), this.mouseTimeoutTime / 3);
}
};
Animation["prototype"].stop = function (event) {
this.mouseTimeout = window.clearTimeout(this.mouseTimeout);
if (this.step == 1) {
this.mouseTimeout = window.setTimeout(this["play"].bind(this, -1, undefined), this.mouseTimeoutTime);
}
};
Animation["prototype"].quit = function (event) {
if (event["relatedTarget"] || this.currentFrame == 1) {
return;
}
this.mouseTimeout = window.setTimeout(this["play"].bind(this, -1, undefined), this.mouseTimeoutTime);
};
var FlyTip = function (animation, textId) {
Listener.call(this,this);
this.animation = animation;
var textDiv = document.getElementById(textId);
this.el = textDiv.cloneNode(true);
this.el.id = this.animation.el.id + "-tt";
this.el.className = textDiv.className;
this.el["style"].display = "none";
var divs = this.el.getElementsByTagName("div");
for(i=0;i<divs["length"];i++){
if(divs[i].className == textId+"-text"){
var textTextDiv = divs[i];
this.panelElement = textTextDiv.appendChild(document.createElement("span"));
this.panelElement.appendChild(document.createTextNode(
this.animation.el.getAttribute("title")));
this.animation.el.setAttribute("title", "");
}
}
document["body"].appendChild(this.el);
this.isShowing = false;
this.listen(this.el, "mouseover", this.start);
this.listen(this.el, "mouseout", this.stop);
};
FlyTip.inherits(Listener);
FlyTip["prototype"].start = function (event) {
window.clearTimeout(this.animation.mouseTimeout);
};
FlyTip["prototype"].stop = function (event) {
window.clearTimeout(this.animation.mouseTimeout);
this.animation.mouseTimeout = window.setTimeout(this.animation["play"].bind(
this.animation, -1, this.animation.frames - 2), this.animation.mouseTimeoutTime);
};
FlyTip["prototype"].show = function () {
this.isShowing = true;
var textDivStyle = this.el["style"];
textDivStyle.visibility = "hidden";
textDivStyle.display = "block";
var height = this.el.offsetHeight;
var width = this.panelElement["offsetWidth"]+14;
var rect = {};
if(this.animation.el.getBoundingClientRect){
var box = this.animation.el.getBoundingClientRect();
rect.left = box["left"];
rect.top = box["top"];
}else{//getBoxObjectFor
var box = document.getBoxObjectFor(this.animation.el);
rect.left = box.x;
rect.top = box.y;
}
textDivStyle.width = width+"px";
textDivStyle.left = rect["left"]-width/2+7+"px";
textDivStyle.top = rect["top"]-height+"px";
textDivStyle.opacity = "1";
textDivStyle.visibility = "visible";
};
FlyTip["prototype"].hide = function () {
this.isShowing = false;
this.el["style"].display = "none";
};
var animations = {};
animations.svcToolbarYSpritePosition = {to:"0px"};
animations.svcToolbarFrames = 7;
animations.svcToolbarAnimationSpeed = 75;
animations.svcToolbarMouseoutTime = 100;
animations.init = function () {
var svcToolbarElement = document.getElementById("svc-toolbar");
var allA = svcToolbarElement.getElementsByTagName("a");
for (var i = 0, j = allA["length"]; i < j; i++) {
var aElement = allA[i], aIdnotI = aElement.id.replace("-i", "");
var animation = new Animation(aElement, animations.svcToolbarFrames, animations.svcToolbarYSpritePosition[aIdnotI], animations.svcToolbarAnimationSpeed, animations.svcToolbarMouseoutTime, "tt");
}
try {
document.execCommand("BackgroundImageCache", false, true);
}
catch (Error) {
}
};
var _anis = animations;
(function () {
_anis.init();
})();