您的位置:首页 > Web前端 > JQuery

用原生javascript实现jQuery效果——自定义javascript扩展DOM函数及功能

2012-12-13 13:18 1136 查看
几天前参考了一本关于jQuery的国内的书,学习了如何用原生的javascript实现jQuery的"功能"——自定义函数扩展DOM功能,来仿制部分的jQuery效果。因为发现这样的方法可以在无法使用jQuery的时候(例如和其他框架及自定义函数发生冲突)对想要的效果直接构造实现(只为一小部分功能)。这里主要是关注构造和实现的过程。

首先来看事情的起因:n天前,在一个自己东拼西凑(主要是拼凑了两个别人的首页幻灯图片切换js)帮别人做的一个页面上,试图用jQuery增加一些动态更美观,于是对某个用于登录的表单窗口进行隐藏,并打算用slideDown()进行动态弹出出控制。在脚本没有任何错误的情况下,发现无论如何没有效果。在firefox中打开web控制台,调用动作没有响应,感觉$初始化未起作用,于是更换为函数方法调用,出现这样的报错:



$(...).is is not a function

不得其解,后来逐一排除,发现当我删掉其他几个js的脚本调用时,恢复了正常。最后把问题确认在了一个名为ntes_jslib_1.x.js的脚本上:

<script language="javascript" src="js/ntes_jslib_1.x.js" type="text/javascript" charset=utf-8></script>

这是一个网上找来到滑动切换的脚本,未打开细看。发现把此脚本去除就恢复正常。由此确定是jQuery与它发生的冲突。于是思考解决办法。down来的脚本没有细看,更换其他框架又不求甚解(虽然本来也没有去刨根问底)。于是想到用原生方法能否实现(仅仅为了一个小动态,不再使用jQuery)。这便回忆起之前在一本书上对扩展DOM的了解(书名为《犀利开发jQuery内核详解与实践》,作者:朱印宏)。于是找回书本进行尝试。

对于扩展DOM函数功能来说,DOM与javascript具有不同的“作用域”,由书上的例子来说,下面的功能是无法实现的:

var appendTo()=function(e){
e.appendChild(this);
return this;
}

window.onload=function(){
var div=document.getElementsByTagName("div")[0];
var h1=document.createElement("h1");
h1.appendTo(div);//调用自定义的方法,实际无法实现
}

因此,扩展DOM的必要就在于在使用javascript扩展功能之前,为其提供作用的基础。

对于DOM的扩展,因为浏览器的两大派别(其实还是因为神IE的不支持HTMLElement类型),有两种需要:对HTMLElement类型原型对象添加自定义方法(IE不支持),和对DOM节点绑定自定义方法(for IE)。

详细的实现如下:

var DOMextend=function(name,fn){
if(!document.all)//用于判断非IE
eval("HTMLElement.prototype."+name+"=fn");
else{//IE
var _createElement=document.createElement;//存储原方法
document.createElement=function(tag){//重写方法,为createElement()绑定自定义
var _elem=_createElement(tag);//首先加入原方法
eval("_elem."+name+"=fn");//绑定自定义,下同
return _elem;
}
var _getElementById=document.getElementById;
document.getElementById=function(id){//为getElementById()绑定自定义
var _elem=_getElementById(id);
eval("_elem."+name+"=fn");
return _elem;
}
var _getElementsByTagName=document.getElementsByTagName;
document.getElementsByTagName=function(tag){//为getElementsByTagName()绑定自定义
var _arr=_getElementsByTagName(tag);
for(var _elem=0;_elem<_arr.length;_elem++)
eval("_arr[_elem]."+name+"=fn");
return _arr;
}
}
};


由此之后,在构造了DOMextend()方法的基础上,就可以继续扩展和构造其他的自定义函数:

我想要模仿的,是jQuery的slideDown()功能,因此我需要先构造的方法有:

getStyle()用于获取元素样式,offset()用于获取绝对偏移位置,fromStyle()用于将样式值转换为数值进行运算,setCSS()用于设置元素样式,resetCSS()用于设置样式之后恢复样式,以及width()和height()用于获取元素的宽和高。

详细如下:

DOMextend("getStyle",function(n){
var _this=this;
if(_this.style
){
return _this.style
;
}
else if(_this.currentStyle){
return _this.currentStyle
;
}
else if(document.defaultView && document.defaultView.getComputedStyle)
{
n=n.replace(/([A-Z])/g,"-$1");
n=n.toLowerCase();
var s=document.defaultView.getComputedStyle(_this,null);
if(s)
return s.getPropertyValue(n);
}
else
return null;
})
DOMextend("offset",function(){
var _this=this;
var left=0,top=0;
while(_this.offsetParent){
left+=_this.offsetLeft;
top+=_this.offsetTop;
_this=_this.offsetParent;
}
return{
"left":left,
"top":top
};
})
DOMextend("fromStyle",function(w,p){
var _this=this;
var p=arguments[2];
if(!p)
p=1;
if(/px/.test(w) && parseInt(w))
return parseInt(parseInt(w)*p);
else if(/\%/.tese(w)&&parseInt(w)){
var b=parseInt(w)/100;
if((p!=1)&&p)
b*=p;
_this=_this.parentNode;
if(_this.tagName=="BODY")
throw new Error("无尺寸!");
w=_this.getStyle("width");//方法之间很多穿插使用
return arguments.callee(_this,w,b);
}
else if(/auto/.test(w)){
var b=1;
if((p!=1)&&p)
b*=p;
_this=_this.parentNode;
if(_this.tagName=="BODY")
throw new Error("无尺寸!");
w=_this.getStyle("width");
return arguments.callee(_this,w,b);
}
else
throw new Error("特殊单位!");
})
DOMextend("setCSS",function(o){
var _this=this;
var a={};
for(var i in o){
a[i]=_this.style[i];
_this.style[i]=o[i];
}
return a;
})
DOMextend("resetCSS",function(o){
var _this=this;
for(var i in o){
_this.style[i]=o[i];
}
})
DOMextend("width",function(){
var _this=this;
if(_this.getStyle("display")!="none")
return _this.offsetWidth||_this.fromStyle(_this.getStyle("width"));
var r=_this.setCSS({
display:"",
position:"absolute",
visibility:"hidden"
});
var w=_this.offsetWidth ||_this.fromStyle(_this.getStyle("width"));
_this.resetCSS(r);
return w;
})
DOMextend("height",function(){
var _this=this;
if(_this.getStyle("display")!="none")
return _this.offsetHeight||_this.fromStyle(_this.getStyle("height"));
var r=_this.setCSS({
display:"",
position:"absolute",
visibility:"hidden"
});
var h=_this.offsetHeight ||_this.fromStyle(_this.getStyle("height"));
_this.resetCSS(r);
return h;
})


最后,万事俱备,构造slideDown():

DOMextend("slideDown",function(time,fn){
var _this=this;
var isShow=_this.getStyle("display");
if(isShow!="none")
return;
var oldcss=_this.setCSS({
display:"",
visibility:"hidden"
})
var x=_this.offset().left;
var y=_this.offset().top;
var height=_this.height();
var width=_this.width();
_this.resetCSS(oldcss);
_this.style.display="";
var box=_this.cloneNode(true);
for(var i=0;i<box.childNodes.length;i++){
box.removeChild(box.childNodes[i]);
}
_this.parentNode.insertBefore(box,_this);
_this=_this.parentNode.removeChild(_this);
box.appendChild(_this);
box.style.overflow="hidden";
box.style.display="";
box.style.height=0;
box.style.width=width;
var step=5;
var stepheight=step*height/time;
var curstep=0;
var interval=setInterval(function(){
if(curstep>=height){
clearInterval(interval);
_this=_this.parentNode.removeChild(_this);
box.parentNode.insertBefore(_this,box);
box.parentNode.removeChild(box);
fn();
}
else{
curstep+=stepheight;
box.style.height=curstep+"px";
}
},step);
})


在我需要调用的部分进行调用:

js部分:

function bonce(){
var hiddes=document.getElementById("hiddenlog");
hiddes.slideDown(300,function(){;}//暂不需要回调函数,空语句
);}


页面部分:

<!----login start-->
<div id="login">
<div id="loginmen">
<img src="images/glydl.png" id="loginbonce" onclick="bonce()"/>
</div>
<div id="loginsub">
<div id="hiddenlog" style="display:none;">
<!--被隐藏的部分-->
</div>
</div>
</div>
<!--login end-->


由此我得以在不使用jQuery的条件下构造出slideDown()方法达到需要的效果。





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: