大家好,我是IT修真院上海分院1期的Web学员刘洪利,今天给大家分享一下关于JavaScript中常见的DOM操作
1.背景介绍
什么是DOM?简单地说,DOM是一套对文档的内容进行抽象和概念化的方法
在现实世界里,人们对所谓的'世界对象模型'都不会陌生,例如,当用'汽车'、'房子'和'树'等名词来称呼日常生活环境里的事物时,我们都可以百分百的肯定对方知道我们说的是什么,这是因为人们在对这些名词所代表的的东西有着相同的认知。于是,当对别人说"汽车停在车库里"时,可以断定他们不会理解为"小鸟关在壁橱里"
我们的"世界对象模型"不进可以用来描述客观存在的事物,还可以同来描述抽象概念。例如,假设有个人想我问路,而我给出的答案是"左边第三栋房子",这个答案有没有意义取决于那个人能够理解"左边"和"第三"的含义。如果他不会数数或者分不清左右,则不管他是否理解这几个概念,我的回答对他都不会有任何的帮助。在现实世界中,正是因为大家对抽象的"世界对象模型"有着基本的共识,人们才能用非常简单的话来表达出复杂的含义并得到对方的理解。
而DOM的定义则是由W3C所制定的标准,定义为"一个与系统平台和编程语言无关的接口,程序和脚本可以通过这个接口动态地访问和修改文档的内容`、结构和样式。"
2.知识剖析
2.1. 节点是什么
节点这个词是一个网络用语,代表了网络中的一个连接点。一个网络就是由一些节点构成的集合。
在现实世界中,一切事物都由原子构成。原子就是现实世界的节点。但是原子同样还可以进一步分解为更细小的亚原子微粒。这些亚原子微粒同样也是节点。
DOM也是同样的情况。文档是由节点构成的集合,只不过此时的节点是文档树上的树枝和树叶而已。
在DOM中有许多不同类型的节点。就像原子包含着亚原子微粒那样,也有很多类型的DOM节点包含着其他类型的节点。接下来我们先看看其中的三种:元素节点、文本节点和属性节点。
2.2. 元素节点
在DOM中的原子就是元素节点。
像是我们现在所看到的这个网页,我们在编写时,会用到诸如<body>、<head>、<p>这些元素。如果把Web上的文档比作一座大厦,那么元素就是建造这座大厦的砖块,这些元素在在文档中的布局形成了文档的结构。元素可以包含其他的元素,在我们所看到的页面页中,内容都被包含在在一个<section>元素的内部。而唯一没有被包含在其他元素中的唯一元素是'<html>',他和我们的节点树的根元素,其他的所有元素都被包含在'<html>'中。
2.3. 文本节点
元素节点只是节点类型的一种。如果一份文档完全有一些空白元素构成,他将有一个结构,但这份文档本身将不会包含什么内容。
在我们的ppt首页中,'<p>'元素包含着文本,'分享人:刘洪利'。他就是一个文本节点。在html文档里,文本节点总是被包含在元素节点的内部。
2.4. 属性节点
属性节点用来对元素做出更具体的描述。例如,几乎所有的元素都有一个title属性,而我们可以利用这个属性对包含在元素里的东西做出准确的描述:'<p title="a gentle reminder">这是一个带有温馨提示的p标签</p>'
在DOM中,title="a gentle reminder"是一个属性节点。因为属性总是被放在起始标签里,所以属性节点总是被包含在元素节点中。并非所有的标签都包含着属性,但是所有的属性都被元素包含。
2.5. 常见的DOM操作
获取DOM
通过使用 getElementById() 方法匹配元素的id属性来访问元素节点,对元素节点进行操作
通过使用 getElementsByTagName() 方法匹配元素的tagName来访问元素节点,对元素节点进行操作
通过使用 getElementsByClassName() 方法匹配元素的className来访问元素节点,对元素节点进行操作
值得注意的是, getElementsByTagName() 和 getElementsByClassName() 这两种方法因为其访问的是节点中的可能为复数的属性,所以得到的会是一个以数组的形式来体现出来的元素节点集合,我们可以通过打印获取到的DOM节点来判断类型
DOM事件
onclick事件---当用户点击时执行
onload事件---当用户进入时执行
onunload事件---用用户离开时执行
onmouseover事件---当用户鼠标指针移入时执行
onmouseout事件---当用户鼠标指针移出时执行
onmousedown事件---当用户鼠标摁下时执行
onmouseup事件---当用户鼠标松开时执行
3. 常见问题
如何通过class和tag调用元素?如何对其设置属性?
4.解决方案
在一个页面中常常有多个class相同的元素,也有多个标签相同的元素,在调用时方法如下
5. 扩展思考
onblur事件---当对象失去焦点时发生
onchange事件---当对象域的值被改变时发生
button 事件---属性可返回一个整数,指示当事件被触发时哪个鼠标按键被点击。
更多的事件就不一一的描述了,有兴趣的同学可以去看下这个
6. 参考文献
书籍:《JavaScript DOM编程艺术》
网址:w3school
7.更多讨论
Q:dom操作是异步的吗
A:dom的操作其实是同步的,但是渲染是异步的。因为JavaScript引擎线程跟GUI渲染线程是互斥的,即我执行的时候,你就靠边站,我执行完你才能执行。具体的可以看下这篇文章https://segmentfault.com/a/1190000005803237----《关于修改DOM是异步还是同步的问题》
Q:除了getElementsByClassName()、getElementsByTagName()、getElementById()还有什么可以获取dom节点的方法
A:
1.通过节点属性得到元素
1)node属性:来获取节点的名称、类型、值。
js代码:
window.onload=function(){ 子节点
var pox = document.getElementById('pox');
alert(pox.childNodes.length) //子节点数量
alert(pox.childNodes[0].nodeValue); // 第一个子节点的内容
alert(pox.firstChild.nodeValue); // 第一个子节点的内容
alert(pox.lastChild.nodeValue); // 最后一个节点的内容
};
注意:node只能获取当前节点的东西,在上面的js代码中node本身把节点指针放在元素上,所以本身没有value值,
2.层次节点属性:层级节点可以分为父子节点和兄弟节点,通过当前节点可以获取其他层次的节点。
2.1)子节点childNodes、第一个字节点firstChilds、最后一个子节点lastChilds。
js代码:
window.onload=function(){ 子节点
var pox = document.getElementById('pox');
alert(pox.childNodes.length) //子节点数量
alert(pox.childNodes[0].nodeValue); // 第一个子节点的内容
alert(pox.firstChild.nodeValue); // 第一个子节点的内容
alert(pox.lastChild.nodeValue); // 最后一个节点的内容
};
2.2)父节点parentChild、兄弟节点previousSibing,nextSibing。
js代码:
window.onload=function(){ 父节点,上下节点
var pox = document.getElementById('pox');
alert(pox.parentNode); //pox节点的父节点body节点
alert(pox.firstChild.nextSibling); //pox节点的子节点中第一个节点的下一个节点
alert(pox.lastChild.previousSibling); //pox节点的子节点中最后一个节点的上一个节点
alert(pox.lastChild.previousSibling.nodeName)
};
本回答摘自-----------《获取元素节点(DOM基础 )》http://blog.csdn.net/u010928364/article/details/43935875
Q:dom操作的最佳实践应该是什么样的
A:
1. 平稳退化:正确的使用JavaScript脚本,让访问者在他们浏览器不支持JavaScript的情况下仍能顺利的浏览你的网站,即是有些功能无法使用,但最基本的操作仍能顺利完成。
2. 分离JavaScript:将HTML内部DOM事件分离到外部来,保证HTML的纯净,同时可以在外部js文件通过获取DOM节点来给这个节点添加事件的形式来运行外部JavaScript文件。
3. 向后兼容:因为不同浏览器对JavaScript的支持程度也不一致,绝大多数的浏览器都可以或多或少的支持JavaScript,,但比较古老的浏览器却很有可能无法理解DOM提供的方法和脚本。因此,我们通过以下几点来确保那些古老的浏览器不会因为脚本代码而出问题。
3.1. 对象检测:检测浏览器对JavaScript的支持程度。我们可以通过将某种方法打包在一个if语句中,然后根据这条语句的条件表达式的求值结果为true(这个方法存在)还是false(这个方法不存在)来决定应该采取怎么样的行动。
例如,如果有一个使用了getElementById()方法的函数么就可以在调用getElementById()方法之前先检查用户所用的浏览器是否支持这个方法。在使用对象检查时,一定要删除方法名后面的圆括号,如果不删掉,测试的将是方法的结果,无论方法是否存在
代码:
if( ! document.getElementById ) return false;
4. 性能考虑: 为保证应用流畅的运行,在为文档编写和应用脚本时,需要注意一些问题。
4.1. 尽量少访问DOM和尽量减少标记
访问DOM的方式对脚本性能会产生很大的影响。例如当我们需要访问html页面中所有的div元素来找到我们想要的那个节点,我们不知道会有多少div元素来面对着我们,所以浏览器会去搜索整个DOM树,从中查找可能匹配的元素。
另一个是尽量减少文档中的标记数量。过多不必要的元素只会增加DOM树的规模,进而增加遍历DOM树以查找特定元素的时间。
4.2. 合并和放置脚本
我们通过合并外部JavaScript文件来减少加载页面时发送的请求数量。减少请求数量通常都是在性能优化时优先考虑的。
4.3. 压缩脚本
通过将脚本文件中不必要耳朵字节,如空格和注释统统删除,从而达到“压缩文件”的目的。
鸣谢
感谢大家观看
分享人:刘洪利
IT修真院上海Web第1期学员刘洪利: 邀请码14898047