下面我们来看一下dom-construct模块是怎么处理的。
找出所有待补全的元素:tbody、thead、tfoot、tr、td、th、caption、colgroup、col、legend、li;dojo中使用如下结构将某些缺失的标签管理起来:
var tagWrap = { option: ["select"], tbody: ["table"], thead: ["table"], tfoot: ["table"], tr: ["table", "tbody"], td: ["table", "tbody", "tr"], th: ["table", "thead", "tr"], legend: ["fieldset"], caption: ["table"], colgroup: ["table"], col: ["table", "colgroup"], li: ["ul"] },
经过下面这一步处理后,tagWrap中的每一项中多了两个属性, eg:tagWrap.tr.pre = "<table><tbody>"和tagWrap.tr.post = "</tbody></table>";
for(var param in tagWrap){ if(tagWrap.hasOwnProperty(param)){ var tw = tagWrap[param]; tw.pre = param == "option" ? '<select multiple="multiple">' : "<" + tw.join("><") + ">"; tw.post = "</" + tw.reverse().join("></") + ">"; } }
1、innerHTML方式需要一个额外的元素,作为临时的容器,所以利用一下变量来管理这个额外的元素:
var reTag = /<\s*([\w\:]+)/,//用来判断字符串参数中是否含有html标签masterNode = {},//作为仓库来管理临时容器 masterNum = 0,//z这两个变量用来标识临时容器masterName = "__" + dojo._scopeName + "ToDomId";
2、toDom方法中,首先创建一个临时容器,是一个div元素:
doc = doc || win.doc; var masterId = doc[masterName]; if(!masterId){ doc[masterName] = masterId = ++masterNum + ""; masterNode[masterId] = doc.createElement("div"); }
3、然后判断frag中是否含有html标签,如果含有html标签而且需要我们补全包装元素,则利用上面生成的pre和post补全标签后传递给master这个容器的innerHTML,这一步完成后找到我们传入的html标签对应的dom树,赋值给master;如果不需要包装,直接赋值给master.innerHTML
var match = frag.match(reTag), tag = match ? match[1].toLowerCase() : "", master = masterNode[masterId], wrap, i, fc, df; if(match && tagWrap[tag]){ wrap = tagWrap[tag]; master.innerHTML = wrap.pre + frag + wrap.post; for(i = wrap.length; i; --i){ master = master.firstChild; } }else{ master.innerHTML = frag; }
这里仅是简单的认为如果正则匹配则进行包装处理,按照我的理解,正则的写法应该为:/^<\s*([\w\:]+)/,原因看下面例子:
第一个表达式子所以报错,就是因为“adffd”这部分在dom中被作为文本节点,文本节点并没有子节点。更改了正则之后,如果不是html标签做开头则统一作为文本节点添加到dom中去。
4、将html标签转化成dom后,如果仅有一个元素则返回这个元素,否则将转化后的元素,放入到文档片段中。
if(master.childNodes.length == 1){ return master.removeChild(master.firstChild); // DOMNode } df = doc.createDocumentFragment(); while((fc = master.firstChild)){ // intentional assignment df.appendChild(fc); } return df; // DocumentFragment
参考标准的描述,DocumentFragment是一个轻量级的文档对象,能够提取部分文档的树或创建一个新的文档片段。可以通过appendChild()或insertBefore()将文档片段中内容添加到文档中。在将文档片段作为参数传递给这两个方法时,实际上只会将文档片段的所有子节点添加到相应的位置上;文档片段本身永远不会称为文档树的一部分
利用innerHTML标签创建dom元素,并自动补齐缺失的标签,这就是dom-construct模块针对toDOM方法的实现思路。
1 exports.toDom = function toDom(frag, doc){ 2 // summary: 3 // instantiates an HTML fragment returning the corresponding DOM. 4 // frag: String 5 // the HTML fragment 6 // doc: DocumentNode? 7 // optional document to use when creating DOM nodes, defaults to 8 // dojo/_base/window.doc if not specified. 9 // returns:10 // Document fragment, unless it's a single node in which case it returns the node itself11 // example:12 // Create a table row:13 // | require(["dojo/dom-construct"], function(domConstruct){14 // | var tr = domConstruct.toDom("<tr><td>First!</td></tr>");15 // | });16 17 doc = doc || win.doc;18 var masterId = doc[masterName];19 if(!masterId){20 doc[masterName] = masterId = ++masterNum + "";21 masterNode[masterId] = doc.createElement("div");22 }23 24 if(has("ie") <= 8){25 if(!doc.__dojo_html5_tested && doc.body){26 html5domfix(doc);27 }28 }29 30 // make sure the frag is a string.31 frag += "";32 33 // find the starting tag, and get node wrapper34 var match = frag.match(reTag),35 tag = match ? match[1].toLowerCase() : "",36 master = masterNode[masterId],37 wrap, i, fc, df;38 if(match && tagWrap[tag]){39 wrap = tagWrap[tag];40 master.innerHTML = wrap.pre + frag + wrap.post;41 for(i = wrap.length; i; --i){42 master = master.firstChild;43 }44 }else{45 master.innerHTML = frag;46 }47 48 // one node shortcut => return the node itself49 if(master.childNodes.length == 1){50 return master.removeChild(master.firstChild); // DOMNode51 }52 53 // return multiple nodes as a document fragment54 df = doc.createDocumentFragment();55 while((fc = master.firstChild)){ // intentional assignment56 df.appendChild(fc);57 }58 return df; // DocumentFragment59 };
联系客服