上一篇讲解dojo/dom-attr的文章中我们知道在某些情况下,attr模块中会交给prop模块来处理。比如:
- textContent、innerHTML、className、htmlFor、value
- disabled、checked等无状态特性对应于属性中的布尔变量
- 事件的处理
那这一节,我们便来看看prop对于属性的处理。
首先是一个标准名称字典,将要设置的属性名重新命名,避免与保留字的冲突:
exports.names = { // properties renamed to avoid clashes with reserved words "class": "className", "for": "htmlFor", // properties written as camelCase tabindex: "tabIndex", readonly: "readOnly", colspan: "colSpan", frameborder: "frameBorder", rowspan: "rowSpan", textcontent: "textContent", valuetype: "valueType" };
相比dom-attr来说,dom-prop模块只有两个公共函数:prop.get与prop.set
prop.get方法的函数签名为:
// Dojo 1.7+ (AMD) require(["dojo/dom-prop"], function(domProp){ result = domProp.get("myNode", "someAttr"); });
除了textContent属性外,其他直接以方括号语法从node中取值:node[prop];对于textContent属性,如果元素不支持textContent,便以深度优先算法去获取元素下所有文本节点的nodevalue:
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; }
因为innerText并不是标准属性,所以这里弃之不用;以下便是get方法的源码:
exports.get = function getProp(/*DOMNode|String*/ node, /*String*/ name){ node = dom.byId(node); //转化成标准属性 var lc = name.toLowerCase(), propName = exports.names[lc] || name; //处理textContent这种特殊属性 if(propName == "textContent" && !has("dom-textContent")){ return getText(node); } return node[propName]; // Anything };
prop.set方法的函数签名为:
require(["dojo/dom-prop"], function(domProp){ result = domProp.set("myNode", "someAttr", "value"); });
在attr.set方法中,很多情况都交给prop来处理,下面我们就要看看prop中set方法的实现。
set方法用来为元素的属性赋值,在实际应用中需要处理以下几种情况:
- 参数分解,如果一次设置多个属性,为每个属性分别设置
- 如果someAttr是“style”,则交给dom-style模块处理
- 如果someAttr是innerHTML,因为有的元素(tbody、thead、tfoot、tr、td、th、caption、colgroup、col)不支持innerHTML属性,所以需要曲线救国,这里首先将元素的子节点清除掉,然后利用dom-construct的toDom方法,将html片段转化成dom节点,作为子节点插入元素中
- 如果someAttr是textContent,同样因为有的浏览器并不支持该属性,曲线救国的方式是先清除元素的子节点,然后创建文本节点作为子节点插入元素中
- 如果value是function,则看做添加事件;对于event的处理最好不要使用prop模块还是推荐使用on模块来绑定事件
exports.set = function setProp(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){ node = dom.byId(node); var l = arguments.length; //分解参数 if(l == 2 && typeof name != "string"){ // inline‘d type check for(var x in name){ exports.set(node, x, name[x]); } return node; // DomNode } //如果要设置style,调用dom-style来处理 var lc = name.toLowerCase(), propName = exports.names[lc] || name; if(propName == "style" && typeof value != "string"){ // inline‘d type check // special case: setting a style style.set(node, value); return node; // DomNode } //如果是innerHTML,对于不支持innerHTML的节点,采用曲线救国的方式,否则直接设置innerHTML if(propName == "innerHTML"){ // special case: assigning HTML // the hash lists elements with read-only innerHTML on IE if(has("ie") && node.tagName.toLowerCase() in {col: 1, colgroup: 1, table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1}){ ctr.empty(node); node.appendChild(ctr.toDom(value, node.ownerDocument)); }else{ node[propName] = value; } return node; // DomNode } //如果不支持textContent,清除元素子节点后,添加文本节点 if(propName == "textContent" && !has("dom-textContent")) { ctr.empty(node); node.appendChild(node.ownerDocument.createTextNode(value)); return node; } //这一部分是通过prop来绑定事件,但并不建议用这种方式 if(lang.isFunction(value)){ // special case: assigning an event handler // clobber if we can var attrId = node[_attrId]; if(!attrId){ attrId = _ctr++; node[_attrId] = attrId; } if(!_evtHdlrMap[attrId]){ _evtHdlrMap[attrId] = {}; } var h = _evtHdlrMap[attrId][propName]; if(h){ //h.remove(); 如果曾经以类似的方式绑定过事件,则移除事件 conn.disconnect(h); }else{ try{ delete node[propName]; }catch(e){} } // ensure that event objects are normalized, etc. if(value){//prop.get函数返回node,所以把handle放到_evtHdlrMap中 //_evtHdlrMap[attrId][propName] = on(node, propName, value); _evtHdlrMap[attrId][propName] = conn.connect(node, propName, value); }else{ node[propName] = null; } return node; // DomNode } node[propName] = value; //直接为属性赋值 return node; // DomNode };
如果您觉得这篇文章对您有帮助,请不吝点击右下方“推荐”,谢谢~
时间: 2024-11-09 16:54:47