zoukankan      html  css  js  c++  java
  • 读Ext之十三(Ext元素)

    终于越来越接近Ext的核心了。这篇开始Ext.Element,这里说的Ext元素指的是Ext.Element类的实例。

    任何前端库都会涉及到对HTMLElement的操作,JQuery更是以其为中心,一个$()函数调用后将DOM元素以索引方式存在 JQuery对象 中。

    Ext则使用了一个称为 Ext.Element 的类,如 Ext.get/Ext.fly 返回的都是该类的实例对象。许多操作如样式,添加事件等都封装到该类里。

    Ext.Element的定义大概框架如下

    Ext.Element = function(element, forceNew){
        var dom = typeof element == "string" ?
                  DOC.getElementById(element) : element,
            id;
    
        if(!dom) return null;
        id = dom.id;
        if(!forceNew && id && Ext.elCache[id]){ // element object already exists
            return Ext.elCache[id].el;
        }
        this.dom = dom;
        this.id = id || Ext.id(dom);
    };
    var D = Ext.lib.Dom,
        DH = Ext.DomHelper,
        E = Ext.lib.Event,
        A = Ext.lib.Anim,
        El = Ext.Element,
        EC = Ext.elCache;
    
    El.prototype = {
        ...
    }
    

    可以看到,采用了的是很传统的JS写类方式:构造器+原型 方式。构造器内执行大概如下

    1,如果参数element是字符串则使用document.getElementById获取,否则直接返回element(通常是HTMLElement)。

    2,给 变量 id赋值,来自dom.id

    3,forceNew不传或传false情况下,优先从缓存中取。

    4,给this挂上dom和id属性。

    3处有点绕人,

    return Ext.elCache[id].el;

    我们知道这是在定义一个类,使用new操作符。如

    var ele = new Ext.Element('head');

    既然是new,里面怎么又return了呢?一般是函数调用(),里面有return。构造器里一般都是定义一些字段。其实当构造器中return的是对象类型时是允许的,如果return的是基本类型,又使用new调用函数则会出现非预期的效果。对于这点感兴趣的详见:具名函数的四种调用方式 系列 。

    构造器内其实很少代码,比较简单。随后是定义了一些变量如D,DH,这些多数是之前篇幅中提到的。Ext采用这种简单的设计模式:组合。Bruce Eckel在《Think in Java》中所言,避免滥用继承,多数情况下组合已足以。

    接着看挂在prototype上的第一个方法 set

    set : function(o, useSet){
        var el = this.dom,
            attr,
            val,
            useSet = (useSet !== false) && !!el.setAttribute;
    
        for(attr in o){
            if (o.hasOwnProperty(attr)) {
                val = o[attr];
                if (attr == 'style') {
                    DH.applyStyles(el, val);
                } else if (attr == 'cls') {
                    el.className = val;
                } else if (useSet) {
                    el.setAttribute(attr, val);
                } else {
                    el[attr] = val;
                }
            }
        }
        return this;
    },
    

    该方法用来设置HTMLElement(如div)的属性如id、style、class等。第一个参数是个对象(Hash)如{id:'uname'},第二个参数布尔类型,顾名思义useSet为true即使用setAttribute来设置属性。

    至于什么使用setAttribute,什么时候使用点操作符(.)给元素设置属性。这里 给出了详尽的解释。

    该方法内部使用for in来遍历对象,我们知道默认情况下 for in 不会去遍历原形链的属性 的。

    对象的hasOwnProperty方法对继承于原形链的属性是 检测不到 的,即返回false。因此这里hasOwnProperty(attr) 这个判断完全是多余的。

    接着看,又是多个if分支

    style,调用DH.applyStyles。但DH.applyStyles方法有bug 。

    cls,设置类名(class)

    useSet为true,使用setAttribute设置

    最后使用中括号操作符(等价于点操作符)

    看下一个方法 is

    is : function(simpleSelector){
        return Ext.DomQuery.is(this.dom, simpleSelector);
    },
    

    该方法用来检测dom元素是否具有给定的css选择器。

    如对于<div id="d1" class="container"></div>,Ext.get('d1').is('.container')返回的是true。注意字符串container前得有个点。因为是css类选择器。

    该方法内部调用Ext.DomQuery.is,暂不提。

    接下来是 focus 方法,

    focus : function(defer, /* private */ dom) {
        var me = this,
            dom = dom || me.dom;
        try{
            if(Number(defer)){
                me.focus.defer(defer, null, [null, dom]);
            }else{
                dom.focus();
            }
        }catch(e){}
        return me;
    },
    

    focus方法用来获取焦点,defer为数字,即延迟函数调用的时间,单位是毫秒。

    参数dom对于使用Ext库的客户端程序员来说是用不到的,仅提供给库内部使用,即递归调用。

    me.focus.defer(defer, null, [null, dom]);
    

    这句较难理解,即递归调用。me是this,this是Ext.Element对象自身。在focus内部又调用自己。

    me.focus.defer 中的 defer哪来的? 还记得第三篇 原型扩展 中提到的为Function.prototype扩展的defer方法吗?没错,就是它。

    如果没有传defer,那么直接调用dom.focus。这里使用了try catch,是因为某些情况下会出异常。

    接下来是 blur 方法,很简单就不说了。往下看 getValue 方法

    getValue : function(asNumber){
        var val = this.dom.value;
        return asNumber ? parseInt(val, 10) : val;
    },
    

    获取元素的value,一般是form内元素如input,select,textarea等。这里很巧妙,如果asNumber为true则偷偷的将其 转换为数字类型 了。

    接下来是 addListener /  removeListener / removeAllListeners / purgeAllListeners ,它们内部使用的是Ext.EventManager。第九篇 提到了,不说了。

    往下是 addUnits 方法,该方法是内部用的。暂不提。

    接下来是 load 方法

    load : function(url, params, cb){
        Ext.Ajax.request(Ext.apply({
            params: params,
            url: url.url || url,
            callback: cb,
            el: this.dom,
            indicatorText: url.indicatorText || ''
        }, Ext.isObject(url) ? url : {}));
        return this;
    },
    

    该方法把请求返回的html片段作为该元素的innerHTML填充。内部调用的是Ext.Ajax.request。

    接着是isBorderBox 方法

    isBorderBox : function(){
        return noBoxAdjust[(this.dom.tagName || "").toLowerCase()] || Ext.isBorderBox;
    },
    

    标准模式中对于具有border的元素如select会返回1,怪异模式中对于input,select,textarea元素返回1。如果不是这些元素会直接返回Ext.isBorderBox。

    isBorderBox = isIE && !isStrict,
    

     

    接下来是 remove 方法,

    remove : function(){
        var me = this,
            dom = me.dom;
    
        if (dom) {
            delete me.dom;
            Ext.removeNode(dom);
        }
    },
    

    该方法会删除该dom元素,包括dom文档中的,ext缓存中的,及dom元素上的事件handler。

    往下是 hover 方法,

    hover : function(overFn, outFn, scope, options){
        var me = this;
        me.on('mouseenter', overFn, scope || me.dom, options);
        me.on('mouseleave', outFn, scope || me.dom, options);
        return me;
    },
    

    意义及用法就不提了,内部使用me.on,on是addListener的简写。mouseenter和mouseleave 的实现在 第四篇 提到 了。

    接着是 contains 方法,

    contains : function(el){
        return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
    },
    

    判断是否包含el元素,内部实现也在第四篇中提到。

    再看 getAttribute 方法,

    getAttribute : Ext.isIE ? function(name, ns){
        var d = this.dom,
            type = typeof d[ns + ":" + name];
    
        if(['undefined', 'unknown'].indexOf(type) == -1){
            return d[ns + ":" + name];
        }
        return d[name];
    } : function(name, ns){
        var d = this.dom;
        return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name) || d.getAttribute(name) || d[name];
    },
    

    该方法用来获取元素的属性值。可以看到对于IE和非IE有两个版本,IE中对undefined,unknow类型做了处理。其它浏览器则是标准的实现。

    最后一个是 update 方法,

    update : function(html) {
        if (this.dom) {
            this.dom.innerHTML = html;
        }
        return this;
    }
    

    该方法使用innerHTML来更新元素内容。

    Element.js

     

  • 相关阅读:
    从一个程序的Bug解析C语言的类型转换
    Expression Blend使用笔刷
    Expression Blend入门
    C#生成CHM文件(中级篇)
    C#生成CHM文件(应用篇)
    C#创建不规则窗体的几种方式
    Web Service学习笔记(2)
    C#生成CHM文件(应用篇)之代码库编辑器(1)
    ASP.NET实际项目演练(1)
    Web Service学习笔记(4)
  • 原文地址:https://www.cnblogs.com/snandy/p/2485835.html
Copyright © 2011-2022 走看看