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

ExtJs源码分析与学习—ExtJs元素Element(一)

2011-07-28 23:22 573 查看
从这一节开始分析ExtJs对元素(Element)的封装与扩展,首先看Ext.lib.Dom 类Ext.lib.Dom 该类源代码对应的文件为ext-base-dom.js。Ext.lib.Dom主要实现了对document中元素部分方法的兼容性实现。在前面事件(Ext.EventManager)的讲解中已经用到了该类。
该类的实现采用了匿名闭包自执行函数实现,执行完该函数,把封装好的对象赋给了对象Ext.lib.Dom,实现了对该类的封装,这种实现的好处把不需要暴露的变量封装到闭包中,同时这些变量的作用域随Ext.lib.Dom自始自终,而不是调用后立马回收。援引别人写的一段话“严格意义上讲任何一个function在执行时就构成一个闭包,闭包的实质是作用域。普通的function,内部声明的变量在执行完会全被回收掉,这时闭包也被回收了,所以这种闭包对我们没有用处,他只是个作用域。如果一个function的局部变量在执行时被生命周期更长的变量引用,那么这个function执行完时就不能回收掉这个局部变量,这个局部变量的生命周期超出了他的作用域,这时的作用域也不能被回收掉,就形成了典型的闭包。闭包的作用就是使局部变量拥有更大的生命周期,甚至全局的生命周期,这使得闭包可以保存function执行时的状态,特别是那种function中又返回一个function时,被返回的function就可以访问父function执行时的所有局部变量(典型的带状态函数)。因为JS中回收一个变量不是看作用域是否结束,而是看引用数。” 先看Ext.lib.Dom一些变量的声明 Js代码

var doc = document,
isCSS1 = doc.compatMode == "CSS1Compat",
MAX = Math.max,
ROUND = Math.round,
PARSEINT = parseInt;
这些变量的声明一是全局管理,二是可以提高js文件代码的压缩率,http://yui.2clics.net/ 可以在线压缩js文件。
isCSS1用来判断浏览器的文档模式(doctype),true为标准模式,false为怪异模式。在Ext类中用Ext.isStrict来判断,这里采用isCSS1,实现的功能是一样的。
下面看Ext.lib.Dom中方法的定义,首先看方法isAncestor Js代码

isAncestor : function(p, c) {
var ret = false;

p = Ext.getDom(p);
c = Ext.getDom(c);
if (p && c) {
if (p.contains) {
return p.contains(c);
} else if (p.compareDocumentPosition) {
return !!(p.compareDocumentPosition(c) & 16);
} else {
while (c = c.parentNode) {
ret = c == p || ret;
}
}
}
return ret;
},
该方法的功能为判断c是否是p的子元素,并且实现了各浏览器的兼容contains和compareDocumentPosition,关于这两个方法的讲解,参照 javascript contains和compareDocumentPosition 方法来确定是否HTML节点 。在ext-base-event.js Ext.lib.EventObject 中有类似实现elContains。

接下来是返回文档和页面视图高宽,代码如下: Js代码

/**
* 如果full为真返回页面的实际宽度,否则返回可视宽度
* 实际宽度指整个页面的宽度,包括滚动条看不到的区域,而可视宽度指当前可以看到的宽度
*/
getViewWidth : function(full) {
return full ? this.getDocumentWidth() : this.getViewportWidth();
},

/**
* 如果full为真返回页面的实际高度,否则返回可视高度
*/
getViewHeight : function(full) {
return full ? this.getDocumentHeight() : this.getViewportHeight();
},

/**
* 得到页面的实际高度
*/
getDocumentHeight: function() {
return MAX(!isCSS1 ? doc.body.scrollHeight : doc.documentElement.scrollHeight, this.getViewportHeight());
},

/**
* 得到页面的实际宽度
*/
getDocumentWidth: function() {
return MAX(!isCSS1 ? doc.body.scrollWidth : doc.documentElement.scrollWidth, this.getViewportWidth());
},

/**
* 得到页面的可视高度
*/
getViewportHeight: function(){
return Ext.isIE ?
(Ext.isStrict ? doc.documentElement.clientHeight : doc.body.clientHeight) :
self.innerHeight;
},

/**
* 得到页面的可视宽度
*/
getViewportWidth : function() {
return !Ext.isStrict && !Ext.isOpera ? doc.body.clientWidth :
Ext.isIE ? doc.documentElement.clientWidth : self.innerWidth;
},
这一组方法可以分为两类,返回页面的实际高宽度和返回页面的可视宽度,当出现滚动条时,实际高宽度会大于可视高宽度,方法处理了不同浏览器之间的兼容。关于效果请看以下例子 Html代码

<!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" lang="zh-CN">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Ext中getDocumentWidth与getViewportWidth的区别</title>
<link rel="stylesheet" type="text/css"
href="../ext-3.3.1/resources/css/ext-all.css" />
<script type="text/javascript"
src="../ext-3.3.1/adapter/ext/ext-base-debug.js"></script>
<script type="text/javascript"
src="../ext-3.3.1/ext-all-debug-w-comments.js"></script>
<script type="text/javascript"
src="../ext-3.3.1/src/locale/ext-lang-zh_CN.js"></script>
<script type="text/javascript" src="../ext-3.3.1/src/debug.js"></script>
<script type="text/javascript">
Ext.onReady(function() {
Ext.BLANK_IMAGE_URL = '../ext-3.3.1/resources/images/default/s.gif';
Ext.QuickTips.init();
var dom = Ext.lib.Dom;
alert("页面的实际宽度:"+dom.getDocumentWidth());
alert("页面的可视宽度:"+dom.getViewportWidth());
});
</script>
</head>
<body>
<div style="width:2000px;">
Ext中getDocumentWidth与getViewportWidth的区别Ext中getDocumentWidth与getViewportWidth的区别Ext中getDocumentWidth与getViewportWidth的区别
Ext中getDocumentWidth与getViewportWidth的区别
</div>
</body>
</html>
接下来的方法是获取元素相对于文档的位置 Js代码

/**
* 得到给定元素的left
*/
getX : function(el) {
return this.getXY(el)[0];
},

/**
* 得到给定元素的[top,left]
*/
getXY : function(el) {
var p,
pe,
b,
bt,
bl,
dbd,
x = 0,
y = 0,
scroll,
hasAbsolute,
bd = (doc.body || doc.documentElement),
ret = [0,0];

el = Ext.getDom(el);

if(el != bd){
if (el.getBoundingClientRect) {
b = el.getBoundingClientRect();
scroll = fly(document).getScroll();
ret = [ROUND(b.left + scroll.left), ROUND(b.top + scroll.top)];
} else {//不支持getBoundingClientRect,实现起来比较啰嗦,得循环获得元素在页面中的绝对位置
p = el;
hasAbsolute = fly(el).isStyle("position", "absolute");

while (p) {
pe = fly(p);
x += p.offsetLeft;
y += p.offsetTop;

hasAbsolute = hasAbsolute || pe.isStyle("position", "absolute");

if (Ext.isGecko) {
y += bt = PARSEINT(pe.getStyle("borderTopWidth"), 10) || 0;
x += bl = PARSEINT(pe.getStyle("borderLeftWidth"), 10) || 0;

if (p != el && !pe.isStyle('overflow','visible')) {
x += bl;
y += bt;
}
}
p = p.offsetParent;
}

if (Ext.isSafari && hasAbsolute) {
x -= bd.offsetLeft;
y -= bd.offsetTop;
}

if (Ext.isGecko && !hasAbsolute) {
dbd = fly(bd);
x += PARSEINT(dbd.getStyle("borderLeftWidth"), 10) || 0;
y += PARSEINT(dbd.getStyle("borderTopWidth"), 10) || 0;
}

p = el.parentNode;
while (p && p != bd) {
if (!Ext.isOpera || (p.tagName != 'TR' && !fly(p).isStyle("display", "inline"))) {
x -= p.scrollLeft;
y -= p.scrollTop;
}
p = p.parentNode;
}
ret = [x,y];
}
}
return ret;
},
这里需要说明一下关于方法el.getBoundingClientRect,该方法获得页面中某个元素的左、上、右和下分别相对浏览器视窗的位置。该方法已经不再是IE Only了,FF3.0+和Opera9.5+已经支持了该方法,可以说在获得页面元素位置上效率能有很大的提高,在以前版本的Opera和Firefox中必须通过循环来获得元素在页面中的绝对位置。见代码中不支持的实现。关于该方法的运行效果看以下例子 Html代码

<!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>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>方法getBoundingClientRect Demo</title>
</head>

<body style="width: 2000px; height: 1000px;">
<div id="demo"
style="position: absolute; left: 518px; right: 100px; width: 500px; height: 500px; background: #CC0000; top: 114px;">
Demo为了方便就直接用绝对定位的元素
</div>
</body>
</html>
<script>
document.getElementById('demo').onclick=function (){
if (document.documentElement.getBoundingClientRect) {
alert("left:"+this.getBoundingClientRect().left)
alert("top:"+this.getBoundingClientRect().top)
alert("right:"+this.getBoundingClientRect().right)
alert("bottom:"+this.getBoundingClientRect().bottom)
var X= this.getBoundingClientRect().left+document.documentElement.scrollLeft;
var Y = this.getBoundingClientRect().top+document.documentElement.scrollTop;
alert("Demo的位置是X:"+X+";Y:"+Y)
}
}
</script>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: