目录
动态脚本
使用<script>元素可以向页面中插入JavaScript代码的两种方式:通过src特性包含外部文件;使用这个元素本身来包含代码
动态脚本指的是页面加载时不存在,在将来某一刻需要通过修改DOM动态添加脚本。跟操作HTML元素一样,创建动态脚本也有两种方式:插入外部文件和直接插入JS代码。
(1)插入外部文件
//动态创建<script type="text/javascript" src='/images/loading.gif' data-original="test.js"></script>var script = document.createElement("script");script.type = "text/javascript";script.src='/images/loading.gif' data-original= "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='/images/loading.gif' data-original="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高级程序设计》
原标题:DOM操作技术
关键词:dom