toDom方法用来将html标签字符串转化成DOM节点。1.7之后toDom方法被分配到了dom-construct模块。

require(["dojo/dom-construct"], function(domConstruct){
// Take a string and turn it into a DOM node
var node = domConstruct.toDom("<div>I'm a Node</div>");
});

  dom操作是每位想要有所建树的前端开发者必须要跨过的槛,类库虽好常用有依赖,对于类库里常用的函数,我们要做到知其然知其所以然。toDOM将html转换为dom节点,我能想到的是两种方法:

  • 利用正则表达式,依次匹配出所有标签;首先需要一个正确的正则,其次需要保证正确的节点关系
  • 利用dom的api来做,这个我们可以创建一个元素使用innerHTML来自动转换
  很明显,第二种方法简单,全部交给浏览器去做,我们只需拿到元素的子节点即可;但是innerHTML标签又有它的特殊性:
  • innerHTML取值时会把所有的子元素作为文本输出;
  • 设值时,会先将字符串转化为dom节点,然后用dom节点替换元素中的子元素;此时如果字符串中有特殊标签开头,比如tbody、thead、tfoot、tr、td、th、caption、colgroup、col等;对于必须存在包装元素的标签,浏览器不会为这些标签补全包装元素,或者统一作为文本处理,或者忽略这些标签

    那我们就有必要对html标签进行一些修正,主要是针对必须存在于包装元素的标签;这些标签作为innerHTML赋值会被浏览器忽略,但是如果作为dom节点直接挂载到dom树中,浏览器会为他们自动创建隐含的包装元素。所以在遇到这些标签开头的html片段时,我们需要手动补全缺失的包装元素。

  下面我们来看一下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方法的实现思路。

 exports.toDom = function toDom(frag, doc){
// summary:
// instantiates an HTML fragment returning the corresponding DOM.
// frag: String
// the HTML fragment
// doc: DocumentNode?
// optional document to use when creating DOM nodes, defaults to
// dojo/_base/window.doc if not specified.
// returns:
// Document fragment, unless it's a single node in which case it returns the node itself
// example:
// Create a table row:
// | require(["dojo/dom-construct"], function(domConstruct){
// | var tr = domConstruct.toDom("<tr><td>First!</td></tr>");
// | }); doc = doc || win.doc;
var masterId = doc[masterName];
if(!masterId){
doc[masterName] = masterId = ++masterNum + "";
masterNode[masterId] = doc.createElement("div");
} if(has("ie") <= 8){
if(!doc.__dojo_html5_tested && doc.body){
html5domfix(doc);
}
} // make sure the frag is a string.
frag += ""; // find the starting tag, and get node wrapper
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;
} // one node shortcut => return the node itself
if(master.childNodes.length == 1){
return master.removeChild(master.firstChild); // DOMNode
} // return multiple nodes as a document fragment
df = doc.createDocumentFragment();
while((fc = master.firstChild)){ // intentional assignment
df.appendChild(fc);
}
return df; // DocumentFragment
};

完整代码

dojo/dom-construct.toDom方法学习笔记的更多相关文章

  1. 《JavaScript DOM 编程艺术》 学习笔记

    目录 <JavaScript DOM 编程艺术> 学习笔记 第一章 js简史 第二章 js语法 准备工作 语法 第三章 DOM DOM中的D DOM中的O DOM中的M 第四章 js图片库 ...

  2. 《JavaScript DOM编程艺术》学习笔记(一)

    这本书是我听说学习前端基础入门书籍,于是就开始看了,大概是从5月10号开始看的吧,一直看到现在,差不多要看完了,书是挺厚的...286页,不过比起JAVASCRIPT权威指南来说还是差多了,权威指南才 ...

  3. 《JavaScript DOM编程艺术》学习笔记(二)

    终于开始接着写我的读书笔记了. 17.DOM有insertBefore方法,但并没有提供insertAfter()方法.不过可利用已有的DOM方法和属性编写此函数: function insertAf ...

  4. zepto.1.1.6.js源码中的each方法学习笔记

    each方法接受要遍历的对象和对应的回调函数作为参数,它的作用是: 1.如果要遍历的对象是类似数组的形式(以该对象的length属性值的类型是否为number类型来判断),那么就把以要遍历的对象为执行 ...

  5. 《JavaScript DOM编程艺术》学习笔记(三)

    终于要完成这最后一部分了,距离第二部分已经过去五天了,一直想早点写的,但还是拖到今天了………… 34.position属性的和法制:static是position属性的默认值,意思是有关元素将按照它们 ...

  6. JAVA与DOM解析器基础 学习笔记

    要求 必备知识 JAVA基础知识.XML基础知识. 开发环境 MyEclipse10 资料下载 源码下载   文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的 ...

  7. Java中关于 ArrayList 和 Map 的常用遍历方法 (学习笔记,便于以后查询)

    一.学习ArrayList与Map时,关于常用遍历方法的记录如下:  二.附源码如下: package com.study.in.myself; import java.util.ArrayList; ...

  8. 《Javascript DOM编程艺术》学习笔记 第1-6章

    第1章 Javascript简史 Javascript是Netspace公司与Sun公司合作开发的,Javascript 1.0版于1995年推出. 为与微软公司竞争,Netspace公司和Sun公司 ...

  9. Android Studio调试方法学习笔记

    (注:本人所用Android Studio的Keymap已设为Eclipse copy) 1.设置断点 只有设置断点,才好定位要调试什么地方,否则找不到要调试的地方,无法调试.(调试过程中也可以增加断 ...

随机推荐

  1. Mongodb无法访问28107的问题

    解压mongodb文件后,放到指定文件,最好别有空格.汉字之类的文件中 此时在mongodb文件夹下,建立一个 db 文件夹,此时执行启动命令,默认27017端口号可以打开,但是28017端口无法打开 ...

  2. PC和HOST之间文件传送

    从PC到HOST 文件传送表(*.srl) C:\123.txt text ~'LIANG.TEST.LIB.123' 批处理文件(*.bat) SEND "PC文件全路径" 'H ...

  3. 摘记 pyinstaller 使用自定义 spec

    下面的是官网的文档, 我们可以用自定义spec的方式把想要的文件打包到目标文件夹里面 例如: 我们在程序中用了一个图标 test.ico, 如果我们只用 pyinstaller -w test.py ...

  4. MongoDB GridFS 对图片进行增删改

    using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Builders; using MongoDB.Driver.GridFS ...

  5. 使用C#代码部署SharePoint 2013开发包简单总结(一)

    这篇文章将总结下如何将自己开发的列表.Web部件.事件接收器等元素部署到SharePoint的服务器.因水平有限,我的做法未必是最佳实践,会有些错误理解和疏漏,欢迎各位高手批评指正——但一定要能给出更 ...

  6. Hibernate-list()与iterate()方法的区别

    对于list方法而言,实际上Hibernate是通过一条Select SQL获取所有的记录.并将其读出,填入到POJO中返回.而iterate 方法,则是首先通过一条Select SQL 获取所有符合 ...

  7. 今个忽然晓得,原来radio不是普通去获取值的!

    今日,写js校验.对于不太会的,总是陌生的.碰见radio的取值,习惯的用document.getElementsByName("")[0].value去获取值,却忘记了radio ...

  8. 通过统计用户DNS解析记录,实现监控用户上网行为

    上次通过扫描抓包分析TTL的方式检测公司网络开放的端口,发现没有开放53端口(DNS),也就是在公司内部的主机只能用服务器自动分配的DNS,并且发现这是台内部服务器.今天发现bing上不去,检测后发现 ...

  9. eclipse 配色方案

    http://www.blogjava.net/kuuyee/archive/2013/02/26/395728.html

  10. permutation II (boss出来了)

    题目链接:https://leetcode.com/submissions/detail/55876321/ 自己的做法,30个测试用例通过了29例,终究还是有一个系列类型的是无法通过的,因为自己妄想 ...