`

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

阅读更多

      从这一节开始分析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一些变量的声明

 

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

 

              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。

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

 

        /**
	 * 如果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;
        },

      这一组方法可以分为两类,返回页面的实际高宽度和返回页面的可视宽度,当出现滚动条时,实际高宽度会大于可视高宽度,方法处理了不同浏览器之间的兼容。关于效果请看以下例子

 

<!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>

 接下来的方法是获取元素相对于文档的位置

 

/**
         * 得到给定元素的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中必须通过循环来获得元素在页面中的绝对位置。见代码中不支持的实现。关于该方法的运行效果看以下例子

 

<!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>

 

       接下来是设置元素的x和y坐标,这三个方法依赖于Ext.fly,Ext.fly实际上是Ext.Element.fly和el.translatePoints(xy)(修改元素的left属性值和top属性),接下来会讲解道这两个方法。

 

分享到:
评论
1 楼 tangjikey 2012-05-24  
javascript contains和compareDocumentPosition 方法来确定是否HTML节点
上面文中的链接加错了,应该为
http://linder0209.iteye.com/blog/980826

相关推荐

Global site tag (gtag.js) - Google Analytics