你的位置:首页 > Java教程

[Java教程]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集合中的指定位置插入一个单元格,返回对新插入单元格的引用。
//创建tablevar table = document.createElement('table');table.border = 1;table.width = "100%";//创建tbodyvar 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等返回的都是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高级程序设计》