上層建築——DOM元素的特性與屬性(dojo/dom-attr)

  上一篇返本求源中,咱們從DOM基礎的角度出發,總結了特性與屬性的關係。本文中,咱們來看看dojo框架是如何處理特性與屬性的。dojo框架中特性的處理位於dojo/dom-attr模塊屬性的處理爲與dojo/dom-prop模塊中。html

attr.set()node

  方法的函數簽名爲:算法

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

  「someAttr」表明特性名稱,但有時候也能夠是一些特殊的屬性名,如:‘textContent’:api

  

  能夠看到上圖中使用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()dom

  方法的函數簽名爲:函數

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

  爲了解釋方便,咱們要先看一下get方法的源碼:ui

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.hasthis

  既然能夠使用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);
    };

  

  若是您以爲這篇文章對您有幫助,請不吝點擊右下方「推薦」,謝謝~

相關文章
相關標籤/搜索