Nicholas C. Zakas 博文中提到了前端工程师必须想都不用想都能知道的web开发常识 :
* DOM structure - how nodes are related to one another and how to traverse from one to the next.
* DOM manipulation - how to add, remove, move, copy, create, and find nodes.
* Events - how to use them and the major differences between IE and the DOM event models.
* XMLHttpRequest - what it is, how to perform a complete GET request, how to detect errors.
* Strict vs. quirks modes - how to trigger each and why this matters.
* The box model - how margin, padding, and border are related and how Internet Explorer < 8 does things differently.
* Block vs. inline elements - how to manipulate using CSS, how they effect things around them and your ability to style them.
* Floating elements - how to use them, troubles with them, and how to work around the troubles.
* HTML vs. XHTML - how they’re different, why you might want to use one over the other.
* JSON - what it is, why you’d want to use it, how to actually use it, implementation details.
对这些问题我自认尚不能达到完全明了,这一系列博文就对这些基础问题进行一点总结与研究。
注:部分来源于已有网络资料
修订日期:
2010-01-25 14:50
2010-02-02 已将整理的全部问题完整资料放入 google doc
* DOM结构
两个节点之间可能存在哪些关系以及如何在节点之间任意移动。
http://www.w3.org/TR/DOM-Level-2-Core/core.html
当前节点为node
父节点:node.parentNode
子节点NodeList:node.childNodes 包括文本,注释等节点
注意IE与webkit,gecko核心浏览器区别,ie不会将标签间空白字符也算作文字节点
<div id="test">s
<div></div>
</div>
<script>
alert(document.getElementById("test").childNodes.length);
</script>
第一个子节点:node.firstChild
最后一个子节点: node.lastChild
同一层上一个子节点:node.nextSibling
同一层下一个子节点:node.previousSibling
* DOM操作
怎样添加、移除、移动、复制、创建和查找节点。
核心DOM
http://www.w3.org/TR/DOM-Level-2-Core/core.html
节点的操作:
创建节点:
document.createElement("div"); document.createTextNode("textnode");
创建节点碎片:
document.createDocumentFragment();
防止页面频繁Reflow
添加节点:
parentNode.appendChild(node);//在节点parentNode的子节点后追加node子节点 parentNode.insertBefore(newChild, oldChild); //在 oldChild前插入newChild节点,当oldChild不填时,相当于appendChild //注意不存在:parentNode.insertAfter()
删除节点:
parentNode.removeChild(node)
复制节点:
parentNode.cloneNode(deep); //deep为true时,则为深拷贝同时复制所有子节点,为false时,则只复制该节点//(该节点所有属性都会复制)
替换节点:
parentNode.replaceChild(newNode,oldNode) //将oldNode节点替换为newNode节点。
访问节点:
document.getElementsByTagName(name)
返回带有指定标签名的对象的集合,元素的顺序是它们在文档中的顺序。如果把特殊字符串 "*" 传递给 getElementsByTagName() 方法,它将返回文档中所有元素的列表,元素排列的顺序就是它们在文档中的顺序。
也可node.getElementsByTagName(name) 表示增加约束,只能在node的后代节点中查找。
注意上述返回都为 HTMLCollection 类型,并且是活的,当文档结构改变后,结果也随着改变,比如无限循环问题:
var divs=document.getElementsByTagName("div"); for(var i=0;i<divs.length;i++) { var div=document.createElement("div"); document.body.appendChild(div); }
注意:
标准浏览器还可以使用 dom traversal 操作,目前除了ie都基本支持
http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html
例如:
<div id="test">s <div></div> <input name="child"/> </div> <input name="child"/> <br/> <script> //文档中的所有element节点 var supported=document.implementation.hasFeature("Traversal","2.0"); if(supported){ var iter= document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, null,true); var n=iter.nextNode(); var loop=0; while (n && (++loop<10)) { document.writeln("nodeName :"+ n.nodeName+"<br/>"); n=iter.nextNode(); } }else { document.writeln("DOM 2 Traversal not supported"); } </script>
一点说明:虽然 firefox
document.implementation.hasFeature("Traversal","2.0");
为false,但是traversal api还是能用的.
操作节点属性:
node.getAttribute(name)
得到节点设置的name属性
Node.setAttribute(name,value)
设置节点的name属性
注意上述属性以及属性值都为字符串类型
node.removeAttribute(name)
删除节点的name属性
HTML DOM
http://www.w3.org/TR/DOM-Level-2-HTML/html.html
Document.getElementById(id)
返回对拥有指定 ID 的第一个对象的引用。(注意为第一个)
document.getElementsByName(name)
返回带有指定名称的对象的集合。
HTML DOM 提供了 HTML DOM对象 ,简化了一些操作:
比如:
Select 对象集合
options[]
返回包含下拉列表中的所有选项的一个数组。
add(option)
向下拉列表添加一个选项。
Remove(index)
从下拉列表中删除一个选项。
比如:
Img 为图片DOM节点
Img.width 与 img. getAttribute(“width”) 当节点有width属性时结果一样
但是 img.width 为数字类型,而img. getAttribute(“width”)为字符串类型
当节点没有设置width设置时,img.width可以取得图片本身的值,而img. getAttribute(“width”)为空,可见点取得属性时会动态的得到节点真实的值。
比如:
一些方便的表格属性以及方法:
tr.cells
返回 tr元素中的所有单元格
table.rows
表格中所有行的集合
table.insertRow(position)
用于在表格中的指定位置插入一个新行。返回一个 TableRow,表示新插入的行
table.deleteRow(position)
删除表格指定位置的一行
insertCell(position)
用于在 HTML 表的一行的指定位置插入一个空的 <td> 元素。返回一个 TableCell 对象,表示新创建并被插入的 <td> 元素。请注意,该方法只能插入 <td> 数据表元。若需要给行添加头表元,必须用 Document.createElement() 方法和 Node.insertBefore() 方法(或相关的方法)创建并插入一个 <th> 元素。
deleteCell(position)
删除表格行中的单元格(<td> 元素)。
* 事件
怎样使用事件以及IE和DOM事件模型之间存在哪些主要差别。
冒泡与捕获
事件有两种触发方式, Bubbling(冒泡) 与Capturing(捕获)。,冒泡是当一个DOM节点的某事件例如click事件被触发时,它的父节点的click事件也被触发,一直传递到最顶层的body元素,然后再触发 document 的相应事件。而捕获的触发方式正好相反,当某个元素的click事件被触发时,先触发 document 的相应事件,然后再从最顶层的body元素click事件被触发开始,一直传递到真正被触发的元素为止。
建议采用 DOM-2 事件模型,可以同一元素同一事件绑定多个事件处理器,分为 w3c 标准模型与 IE 模型
http://www.quirksmode.org/dom/w3c_events.html
W3c 标准模型:
http://www.w3.org/TR/DOM-Level-2-Events/events.html
注册事件:
使用addEventListener和removeEventListener,例如
window.addEventListener(‘load’,function(evt){…},false); document.body.addEventListener(‘keypress’,function(evt){…},false); obj.addEventListener(‘mouseover’,MV,true); function MV(evt){…}
addEventListener带有三个参数,第一个参数是事件类型,就是我们熟知的那些事件名字去掉前面的’on’,第二个参数是处理函数,可以直接 给函数字面量或者函数名,第三个参数是boolean值,表示事件是否支持Capturing。
W3C的事件模型优点是Bubbling和Capturing都支持,并且可以在一个DOM元素上绑定多个事件处理器,各自并不会冲突。并且在处理函数内 部,this关键字仍然可以使用只想被绑定的DOM元素。另外function参数列表的第一个位置(不管是否显示调用),都永远是event对象的引 用。
注意:
阻止浏览器的默认行为:event.preventDefault()
阻止事件冒泡:event.stopPropagation()
一些事件属性,event.target 表示事件触发源等细节。
自定义事件与触发:
使用createEvent(参数分别为Events,MouseEvents,UIEvents) 与 initEvent 系列函数,(initMouseEvent ,initUIEvent),使用dispatchEvent 来程序触发事件,注意模拟事件的相应属性在对应的init函数中指定。
例如模拟触发el上的click事件:
var c=document.createEvent("MouseEvents"); //参数一定要和文档一致 c.initMouseEvent("click",true,true,window,1,1,1,1,1,true, true,true,true,1,null); el.dispatchEvent(c);
IE 事件模型:
注册事件:
使用attachEvent和detachEvent两个函数,例如
window.attachEvent(‘onload’,function(){…}); document.body.attachEvent(‘onkeypress’,myKeyHandler);
与W3C的区别是没有第三个参数,而且第一个表示事件类型的参数也必须把’on’给加上。IE 事件模型只支持Bubbling不支持Capturing;在事件处理器的function 内部this等于 window 全局对象。要想得到event对象必须通过window.event方式。
注意:
阻止浏览器的默认行为: window.event.returnValue=false
阻止事件冒泡: window.event.cancelBubble=true
一些事件属性,event.srcElement 表示事件触发源等细节。
自定义事件与触发:
使用 createEventObject 与 fireEvent 触发,注意模拟事件的属性通过eventObject直接添加,
例如模拟click事件:
var evt = document.createEventObject(); el.data="data"; el.fireEvent("onclick",evt);
同样事件要以on为前缀。
20110427 note :
ie9 对于 mousemove 自定义事件的触发有 bug ,无论是 createEventObject 还是 createEvent 对于 clientX,clientY 的理解都有误。