DOM操做技術

目錄javascript

  • 動態腳本
  • 動態樣式
  • 操做表格
  • 使用NodeList

 

動態腳本css

使用<script>元素能夠向頁面中插入JavaScript代碼的兩種方式:經過src特性包含外部文件;使用這個元素自己來包含代碼
動態腳本指的是頁面加載時不存在,在未來某一刻須要經過修改DOM動態添加腳本。跟操做HTML元素同樣,建立動態腳本也有兩種方式:插入外部文件和直接插入JS代碼。
(1)插入外部文件java

//動態建立<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>元素添加到頁面中以前,是不會下載外部文件的。整個過程能夠用函數封裝:chrome

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代碼。app

//針對<=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高級程序設計》

相關文章
相關標籤/搜索