• 上层建筑——DOM元素的特性与属性(dojo/dom-attr)


      上一篇返本求源中,我们从DOM基础的角度出发,总结了特性与属性的关系。本文中,我们来看看dojo框架是如何处理特性与属性的。dojo框架中特性的处理位于dojo/dom-attr模块属性的处理为与dojo/dom-prop模块中。

    attr.set()

      方法的函数签名为:

    require(["dojo/dom-attr"], function(domAttr){
      result = domAttr.set("myNode", "someAttr", "value");
    });

      “someAttr”代表特性名称,但有时候也可以是一些特殊的属性名,如:‘textContent’:

      

      可以看到上图中使用attr设置innerText只会在html标签中增加innerText这个自定义特性,而无法改变文本,使用textContent却能够达到改变文本的目的。其中缘由就是因为在attr模块建立了forceProps字典,在此字典中的key全部使用prop模块来设置:

            forcePropNames = {
                innerHTML:    1,
                textContent:1,
                className:    1,
                htmlFor:    has("ie"),
                value:        1
            }

      set()方法中主要处理以下几件事:

    • “someAttr”除了可以是字符串外,还可以是key-value对象,所以对于key-value对象我们首先要进行参数分解。
    • 如果someAttr等于style,就交给dojo/dom-style模块来处理
    • 上篇文章中我们说过,特性值只能是字符串,所以对于函数,默认是作为事件绑定到元素上,这部分交给dojo/dom-prop来处理;另外对于disabled、checked等无状态的属性,在通过属性设置时,只能传递布尔值,所以这部分也交给prop来处理
    • 剩下的交给原生api,setAttribute来处理,这个方法会自动调用value的toString方法
    exports.set = function setAttr(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){
            node = dom.byId(node);
            if(arguments.length == 2){ // inline'd type check
                // the object form of setter: the 2nd argument is a dictionary
                for(var x in name){
                    exports.set(node, x, name[x]);
                }
                return node; // DomNode
            }
            var lc = name.toLowerCase(),
                propName = prop.names[lc] || name,
                forceProp = forcePropNames[propName];
            if(propName == "style" && typeof value != "string"){ // inline'd type check
                // special case: setting a style
                style.set(node, value);
                return node; // DomNode
            }
            if(forceProp || typeof value == "boolean" || lang.isFunction(value)){
                return prop.set(node, name, value);
            }
            // node's attribute
            node.setAttribute(attrNames[lc] || name, value);
            return node; // DomNode
        };

    attr.get()

      方法的函数签名为:

    // Dojo 1.7+ (AMD)
    require(["dojo/dom-attr"], function(domAttr){
      result = domAttr.get("myNode", "someAttr");
    });

      为了解释方便,我们要先看一下get方法的源码:

    exports.get = function getAttr(/*DOMNode|String*/ node, /*String*/ name){
            node = dom.byId(node);
            var lc = name.toLowerCase(),
                propName = prop.names[lc] || name,
                forceProp = forcePropNames[propName],
                value = node[propName];        // should we access this attribute via a property or via getAttribute()?
    
            if(forceProp && typeof value != "undefined"){
                // node's property
                return value;    // Anything
            }
            
            if(propName == "textContent"){
                return prop.get(node, propName);
            }
            
            if(propName != "href" && (typeof value == "boolean" || lang.isFunction(value))){
                // node's property
                return value;    // Anything
            }
            // node's attribute
            // we need _hasAttr() here to guard against IE returning a default value
            var attrName = attrNames[lc] || name;
            return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
        };
    1. 先得到的是三个变量:propName、forceProp、value,
    2. 如果attrName属于forceProps集合,直接返回DOM节点的属性
    3. textContent明显位于forceProps中,为什么还要单独拿出来做判断?因为有的低版本的浏览器不支持textContent,我们需要利用深度优先算法,利用文本的节点的nodeValue由父到子依次拼接文本,这一点jQuery与dojo的思路都是一致的:
      1. dojo:
        function getText(/*DOMNode*/node){
                var text = "", ch = node.childNodes;
                for(var i = 0, n; n = ch[i]; i++){
                    //Skip comments.
                    if(n.nodeType != 8){
                        if(n.nodeType == 1){
                            text += getText(n);
                        }else{
                            text += n.nodeValue;
                        }
                    }
                }
                return text;
            }
      2. jQuery:
    4. set方法中提到过,对于布尔跟函数,交给prop来设置,那么取值时当然也要从prop中来取;至于为什么要单独拿出href,在“返本求源”中已经说过,通过属性得到的href属性跟getAttribute方法得到的值并不一定相同,尤其是非英文字符:
    5. 由prop模块该做的都做完了,所以这里判断node中是否存在该特性时,无需理会forceProps字典;如果存在则调用getAttribute方法。

    attr.has

      既然可以使用attr来set这些属性,那在attr.has方法中,位于此字典中属性当然也要返回true,所以attr.has(node, attrName)方法主要判断两个方面:

    • attrName是否是forceProps中的key
    • attrName是否是一个特性节点。特性节点为与元素的attributes属性中,可以通过:attributes[attrName] && attributes[attrName].specified 来判断
    exports.has = function hasAttr(/*DOMNode|String*/ node, /*String*/ name){
            var lc = name.toLowerCase();
            return forcePropNames[prop.names[lc] || name] || _hasAttr(dom.byId(node), attrNames[lc] || name);    // Boolean
        };
    function _hasAttr(node, name){
            var attr = node.getAttributeNode && node.getAttributeNode(name);
            return !!attr && attr.specified; // Boolean
        }

      

    attr.remove

      这个方法比较简单,直接调用了removeAttribute方法

    exports.remove = function removeAttr(/*DOMNode|String*/ node, /*String*/ name){
            // summary:
            //        Removes an attribute from an HTML element.
            // node: DOMNode|String
            //        id or reference to the element to remove the attribute from
            // name: String
            //        the name of the attribute to remove
    
            dom.byId(node).removeAttribute(attrNames[name.toLowerCase()] || name);
        };

      

      如果您觉得这篇文章对您有帮助,请不吝点击右下方“推荐”,谢谢~

  • 相关阅读:
    第八次作业-谈谈Java web学习小结
    第七周作业--可行性研究与程序系统的结构
    第六次作业-数据库连接
    第五次作业-系统实现可能需要用到的技术,及学习相关技术的心得
    第四次作业-软件需求分析过程与需求分类
    第三次作业-前端与后台数据交换问题
    第二次作业-软件工作量估算方法
    第一次作业
    捣鼓一个Ajax请求管理器
    动动手,写个knockout的分页模板
  • 原文地址:https://www.cnblogs.com/dojo-lzz/p/4787133.html
Copyright © 2020-2023  润新知