zoukankan      html  css  js  c++  java
  • dojo/dom-construct.toDom方法学习笔记

      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方法的实现思路。

     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 itself
    11         // 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 wrapper
    34         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 itself
    49         if(master.childNodes.length == 1){
    50             return master.removeChild(master.firstChild); // DOMNode
    51         }
    52 
    53         // return multiple nodes as a document fragment
    54         df = doc.createDocumentFragment();
    55         while((fc = master.firstChild)){ // intentional assignment
    56             df.appendChild(fc);
    57         }
    58         return df; // DocumentFragment
    59     };
    完整代码
  • 相关阅读:
    IIS:日志代码分析
    SQL:查找被锁的表,以及锁表的SQL语句(重点推荐)
    SQL 2000/2005/2008 收缩日志方法
    SQL SERVER:使用工具观察与分析数据库中锁信息
    C# : Post 接收或发送XML
    WCF:没有终结点在侦听可以接受消息的*这通常是由于不正确的地址或者 SOAP操作导致的。
    SQL2005 遍历表插入
    SQL2005:SQL Server 2005还原数据库时出现“不能选择文件或文件组XXX_log用于此操作的解决办法
    C#:安装Windows服务,动态指定服务名及描述
    IE6与 javascript:void(0)
  • 原文地址:https://www.cnblogs.com/dojo-lzz/p/4845389.html
Copyright © 2011-2022 走看看