读Ext之五(Dom的低级封装)

上篇看了ext-base-event.js(Ext.lib.Event),这篇看ext-base-dom.js(Ext.lib.Dom)。
后续EventManager.js(Ext.EventManager)其中会用到该篇的Ext.lib.Dom。

整体浏览ext-base-dom.js可以看到还是一个匿名函数执行,与上一篇不同的是这次并非返回包装好的对象pub,而是直接将对象赋值给Ext.lib.Dom。

1
2
3
4
5
6
7
8
(function(){
    var doc = document,
        ...;
         
    Ext.lib.Dom = {       
        ...
    };
})();

 

一些变量声明,

1
2
3
4
5
var doc = document,
    isCSS1 = doc.compatMode == "CSS1Compat",
    MAX = Math.max,    
    ROUND = Math.round,
    PARSEINT = parseInt;

 

doc、Max、ROUND、PARSEINT为简写。好处在上一篇已经提到,clue 还提到了这样写提高了压缩率。即document,Math.max等不会被压缩工具进行名称替换,doc,MAX等则会,可用 YUI Compressor 测试下。

isCSS1用来判断浏览器的文档模式(doctype),为true是标准模式,false是怪异模式。第一篇 提到了Ext.js中有个Ext.isStrict,和这里的isCSS1是一样的。

Ext作者没有使用Ext.isStrict而是新增了一个变量isCSS1个人猜测原因同doc,MAX,亦或是为了保持此处代码一致性。

 

接下来是Ext.lib.Dom对象的定义,先看第一个方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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(child)是否是p(parent)的子节点。这里有contains和compareDocumentPosition各浏览器 兼容列表 。这个方法与ext-base-event.js的私有方法elContains(上一篇已提到)作用类似,不知为何Ext作者要冗余。

接下来是几个获取视图,文档,视窗宽高的方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
getViewWidth : function(full) {
    return full ? this.getDocumentWidth() : this.getViewportWidth();
},
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;
},

这里仅讲述宽。
getViewportWidth 获取视口的宽。即怪异模式且非Opera使用doc.body.clientWidth获取,IE使用doc.documentElement.clientWidth获取,其它浏览器使用self.innerWidth获取。

getDocumentWidth 获取文档的宽。我们知道如果文档中出现水平滚动条,那么文档的宽将大于视口。因此比较scroll宽度和文档宽度,取其中较大的。
这里仍仍然需要区分浏览器的文档模式,怪异模式使用doc.body.scrollWidth,标准模式使用doc.documentElement.scrollWidth获取。

getViewWidth 是对以上两个方法的封装,full为true则取整个文档宽(含滚动),否则只取文档可视区域宽。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
getY : function(el) {
    return this.getXY(el)[1];
},
getX : function(el) {
    return this.getXY(el)[0];
},
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
            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
},

核心是getXY方法,getX和getY都是调用getXY。获取html元素在页面中(窗口客户区域)的位置(top,left)不是件容易的事。
该方法实现用到了Ext.Element相关方法,后续阅读。

接下来是设置元素位置的方法,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
setXY : function(el, xy) {
    (el = Ext.fly(el, '_setXY')).position();
     
    var pts = el.translatePoints(xy),
        style = el.dom.style,
        pos;               
     
    for (pos in pts) {             
        if(!isNaN(pts[pos])) style[pos] = pts[pos] + "px"
    }
},
setX : function(el, x) {
    this.setXY(el, [x, false]);
},
setY : function(el, y) {
    this.setXY(el, [false, y]);
}

核心是setXY,setX和setY都是调用setXY。setXY也依赖于Ext.fly,Ext.fly实际上是Ext.Element.fly。后续阅读。

 

ext-base-dom.js

posted on   snandy  阅读(2323)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
历史上的今天:
2011-04-27 新API解析JSON-Ajax之七
2011-04-27 创建xhr时异常处理-Ajax之六
< 2012年4月 >
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 1 2 3 4 5
6 7 8 9 10 11 12

统计

点击右上角即可分享
微信分享提示