• DOM操作技术


    目录

    • 动态脚本
    • 动态样式
    • 操作表格
    • 使用NodeList

    动态脚本

    使用<script>元素可以向页面中插入JavaScript代码的两种方式:通过src特性包含外部文件;使用这个元素本身来包含代码
    动态脚本指的是页面加载时不存在,在将来某一刻需要通过修改DOM动态添加脚本。跟操作HTML元素一样,创建动态脚本也有两种方式:插入外部文件和直接插入JS代码。
    (1)插入外部文件

    //动态创建<script type="text/javascript" src="test.js"></script>
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src= "test.js";
    document.body.appendChild(script);//这句放哪都可以

    在执行最后一行代码把<script>元素添加到页面中之前,是不会下载外部文件的。整个过程可以用函数封装:

    function loadScript(url){
       var script = document.createElement('script');
       script.type= "text/javascript";
       script.src = url;
       document.body.appendChild(script);
    }
    
    loadScript("test.js");

    加载完成后就可以在页面中其他地方使用这个脚本了。怎么知道脚本什么时候加载(从服务器请求下载过来了)完成了呢,有一些事件可以探知,但要取决于浏览器,支持的浏览器少的可怜。
    <script>(在<=IE10和Opera)和<link>(仅<=IE10)元素会触发readystatechange事件(继承自HTMLElement.prototype.onreadystatechange),可以用来确定外部JavaScript和Css文件是否已经加载完成。当把动态创建的元素添加到页面中浏览器开始下载外部资源,当元素的readyState属性无论等于“loaded”还是“complete”都表示资源已经可用。下面给出一段加载外部JavaScript文件代码(限在<=IE10且支持addEventListener中运行)。

    window.onload = function(e){
      var script = document.createElement('script');
      script.addEventListener('readystatechange', function(e){
         if(e.target.readyState == 'loaded' || e.target.readyState == 'complete'){
             e.target.removeEventListener('readystatechange', arguments.callee, false);
             alert('Script loaded');
         }
      });
      script.src = 'example.js';
      document.body.appendChild(script);
    }

    此时获取<script src="example.js">的readyState的值为“loaded”,与此同时就可以执行已经加载完的外部文件‘example.js’中的函数了。
    (2)行内直接插入JS代码(在除了<=IE8之外浏览器可运行)

    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.appendChild(document.createTextNode("function sayHi(){alert('hi')}"));
    document.body.appendChild(script);

    因为<=IE8将<script>视为一个特殊的元素,不允许DOM访问其子节点,不过可以使用<script>元素text属性(继承自HTMLScriptElement.prototype)来指定JavaScript代码。

    //针对<=IE8和Safari3及之后版本
    var script  = document.createElement('script');
    script.type = 'text/javascript';
    script.text = "function sayHi(){alert('hi')}";
    document.body.appendChild(script);

    兼容所有浏览器的代码

    function loadScriptString(code){
      var script = document.createElement('script');
      script.type = "text/javascript";
      try{
       //除过<=IE8和Safari3及之后版本
       script.appendChild(document.createTextNode(code));
      }catch(e){
        script.text = code;
      }
      document.body.appendChild(script);
    }

    实际上这样执行代码与在全局作用域中把相同的字符串传递给eval()是一样的。

    动态样式

    能够把CSS样式包含到HTML页面中的元素有<link>和<style>
    (1).动态样式是指在页面刚加载时不存在的样式,动态样式是在页面加载完后动态添加到页面中的。

    function loadStyles(url){
      var link = document.createElement("link");
      link.rel = "stylesheet";
      link.type = "text/css";
      link.href = url;
      var head = document.getElementsByTagName('head')[0];
      head.appendChild(link);
    }

    加载外部样式文件的过程是异步的,即加载样式与执行JavaScript代码的过程没有固定次序。在<=IE10且支持addEventListener的IE中可以利用几种事件来检测样式是否加载完成

    window.onload = function(e){
       var link = document.createElement('link');
       link.type = "text/css";
       link.rel = "stylesheet";
       link.addEventListener('readystatechange', function(e){
         if(e.target.readyState == 'loaded' || e.target.readyState == 'complete'){
            e.target.removeEventListener('readystatechange', arguments.callee, false);
            alert('css loaded');
         }
      });
      link.href ="example.css";
      document.getElementsByTagName('head')[0].appendChild(link);
    }

    此时获取<link href="example.css">的readyState的值为“complete”。
    (2).使用<style>元素来包含嵌入式CSS

    var style = document.createElement('style');
    style.type = "text/css";
    style.appendChild(document.createTextNode("body{background-color: red}"));
    var head = document.getElementsByTagName('head')[0];
    head.appendChild(style);

    同样<=IE8将<style>视为一个特殊的,与<script>类似的节点不允许访问其子节点。解决这个问题就是访问元素的styleSheet属性(继承自HTMLStyleElement.prototype),注意这个属性只在<=IE10有,其他浏览器(chrome和FF)经测试还没有,这个属性指向一个CSSStyleSheet类型的一个实例。这个实例属性又继承了CSSStyleSheet.prototype的cssText属性,该属性值可以接受CSS代码。下图测试结果为IE10仿真。

    兼容所有浏览器代码

    function loadStyleString(css){
       var style = document.createElement('style');
       style.type = "text/css";
       try{
          style.appendChild(document.createTextNode(css));
       }catch(e){
          style.styleSheet.cssText = css;
       } 
       var head = document.getElementsByTagName("head")[0];   
       head.appendChild(style);
    }

    注意经cssText设置之后,再通过style.styleSheet.cssText访问该值时候返回的是大写字符串,如图


    操作表格

    为方便构建表格,HTML DOM还为<table>,<tbody>,<tr>元素添加了些属性和方法。先来看看它们都有啥方法和属性。
    (1).table.__proto__->HTMLTableElement.prototype->HTMLElement.prototype->Element.prototype->Node.prototype->EventTarget.prototype->Object.prototype

    • caption:保存着对<caption>元素(如果有)的指针
    • tBodies:是一个<tbody>元素的HTMLCollection
    • tFoot:保存着对<tfoot>元素(如果有)的指针
    • tHead:保存着对<tHead>元素(如果有)的指针
    • rows:是一个表格中所有行的HTMLCollection
    • createTHead():创建<thead>元素,并自动将其放到表格中,返回该<thead>引用。注意若表格中已经存在thead元素,此时调用createTHead()再创建无效,Chrome不会报错,返回原表格中的那个thead元素,其他浏览器还没测试。但一个表格中是可以存在多个thead元素的(通过HTML代码,Chrome渲染没什么错),当在已存在thead元素的表格中再调用该方法无效,返回原表格中第一个thead元素。
    • createTFoot():创建<tfoot>元素,并自动将其放到表格中,返回该<tfoot>引用。注意问题同上。
    • createCaption():创建<caption>元素,并自动将其放到表格中,返回该<caption>引用。注意问题同上。
    • createTBody():创建<tbody>元素,并自动将其放到表格中,返回该<tbody>引用,可多次创建tbody。
    • deleteTHead():从前往后删除<thead>元素。
    • deleteTFoot():从前往后删除<tfoot>元素
    • deleteCaption():从前往后删除<caotion>元素
    • deleteRow(pos):删除指定位置的行。
    • insertRow(pos):向rows集合中指定位置插入一行,返回新插的那行<tr>元素

    (2).tbody.__proto__->HTMLTableSectionElement.prototype->HTMLElement.prototype->Element.prototype->Node.prototype->EventTarget.prototype->Object.prototype

    • rows:保存着<tbody>元素中行的HTMLCollection
    • deleteRow(pos):删除指定位置的行
    • insertRow(pos):向rows集合中的指定位置插入一行,返回被插入新行的引用。

    (3).tr.__proto__->HTMLTableRowElement.prototype->HTMLElement.prototype->Element.prototype->Node.prototype->EventTarget.prototype->Object.prototype

    • cells:保存着tr元素中单元格的HTMLCollection
    • deleteCell(pos):删除指定位置单元格
    • insertCell(pos):向cells集合中的指定位置插入一个单元格,返回对新插入单元格的引用。
    //创建table
    var table = document.createElement('table');
    table.border = 1;
    table.width = "100%";
    
    //创建tbody
    var tbody = document.createElement("tbody");
    table.appendChild(tbody);
    
    //创建第一行
    tbody.insertRow(0);
    tbody.rows[0].insertCell(0);
    tbody.rows[0].cells[0].appendChild(document.createTextNode("cell 1,1"));
    tbody.rows[0].insertCell(1);
    tbody.rows[0].cells[1].appendChild(document.createTextNode("cell 1,2"));
    
    //创建第二行
    tbody.insertRow(1);
    tbody.rows[1].insertCell(0);
    tbody.rows[1].cells[0].appendChild(document.createTextNode("cell 2,1"));
    tbody.rows[1].insertCell(1);
    tbody.rows[1].cells[1].appendChild(document.createTextNode("cell  2,2"));
    
    //表格添加到文档中
    document.body.appendChild(table);

    使用NodeList

    NodeList NamedNodeMap HTMLCollection 这三个集合都是动态的,除了有个例。
    NodeList :getElementsByName,childNodes,querySelectorAll(静态集合)等返回的都是NodeList实例
    HTMLCollection:getElementsByTagName,getElementsByClassName,getElementsByTagNameNS,document.forms,document.children等返回的都是HTMLCollection实例
    NamedNodeMap:表示属性节点对象的集合,ele.attributes返回NamedNodeMap实例

    访问DOM文档时实时运行的查询,所以下面代码会导致无限循环。

    var divs = document.getElementsByTagName('div'),i,div;
    for(i = 0;i< divs.length; i++){
       div = document.createElement('div');
       document.body.appendChild(div);
    }

    浏览器不会将创建的所有集合都保存在一个列表中,而是在下次访问集合时再更新集合,i和divs.length每次都会同时递增,结果它们的值永远不会相等。正确写法如下:

    var divs = document.getElementsByTagName('div'),i,len,div;
    for(i = 0,len = divs.length; i<len;i++){
       div = document.createElement('div');
       document.body.appendChild(div);
    }

    参考

    《JavaScript高级程序设计》

  • 相关阅读:
    力扣(LeetCode)922. 按奇偶排序数组 II
    力扣(LeetCode)1002. 查找常用字符
    力扣(LeetCode)15. 三数之和
    Java == 和 equals 区别
    力扣(LeetCode)125. 验证回文串
    力扣(LeetCode) 905. 按奇偶排序数组
    力扣(LeetCode)832. 翻转图像
    力扣(LeetCode) 771. 宝石与石头
    Sticks
    荷马史诗
  • 原文地址:https://www.cnblogs.com/venoral/p/5401382.html
Copyright © 2020-2023  润新知