相信大家在DOM的实际开发与学习过程中,肯定也遇到不少需要比较的东西,这里我主要列比较以下几点,更多的区别和总结,希望想到和遇到的朋友给我留言哦。
- clientHeight/scrollHeight/offsetHeight
- defer vs async
- 事件模型-捕获/目标/冒泡
- 普通事件 vs 事件绑定
- stopPropagation/preventDefault/return false
- target/currentTarget
文中示例显示不是很好,可以直接去小弟博客看原文:DOM中的各种区别小节
各种height/width
CSS盒模型是比较复杂的,尤其是当页面中有滚动条时,仅仅通过css来操作高度宽度是不够的,幸运的是Javascript提供了不少这样的接口。Javascript中clientHeight
/ cliengWidth
, scrollHeight
/ scrollWidth
, offsetHeight
/ offsetWidth
, height
/ width
都可以获取高度和宽度,但是他们有一些细微的差别:
See the Pen 各种height/width区别 by superlin (@superlin) on CodePen.
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>-
offsetHeight
/offsetWidth
:可见区域包含border
,对于display:block
的元素通过width/height + padding + border
可以计算出来。 -
clientHeight
/cliengWidth
:可见区域包含padding
,不包含border
和滚动条,不能通过CSS样式计算出来,取决于滚动条的大小。 -
scrollHeight
/scrollWidth
:内容区域的大小,不包含border
,包含不在可见区域内的隐藏部分,不能通过CSS样式计算出来。 -
height
/width
:不包含border
和padding
。
另外:滚动条的宽度可以通过如下方式计算:
javascript
scrollbarWidth = offsetWidth - clientWidth - getComputedStyle().borderLeftWidth - getComputedStyle().borderRightWidth
defer与async
<script>
标签的defer
和async
属性大多数浏览器都已经支持了(IE9以下不支持defer
),那么他们到底有什么区别呢?这里我们用几张图来描述,相信看完之后你就很清楚他们的区别了,首先对于图示做如下说明:
<script>
:如果script
不带任何属性,这种情况下HTML文档遇到js脚本就会中止解析,先发送请求下载文件,下载完成后执行脚本,之后再继续解析HTML文档。
<script async>
:带有async
属性时,js脚本下载不会使HTML文档解析中止,下载完成后才会中止文档解析,执行完成后再继续解析文档。
<script defer>
:带有defer
属性时,js脚本下载不会使HTML文档解析中止,而且js执行都是在文档解析完成之后。
一般情况下,能用async
就用async
,然后是defer
,最后才是什么属性都不带,主要的规则如下:
- 如果当前脚本是模块化的,而且不依赖其他脚本,使用
async
- 如果当前脚本依赖于其他脚本或被其他脚本所依赖,使用
defer
- 如果脚本文件很小,而且被其他
async
脚本依赖,可以将当前脚本作为内联脚本放在那些async
脚本的前面
事件捕获与冒泡
先来看一个简单的问题,假设有一个element1元素,里面还有一个element2元素。
-----------------------------------
| element1 |
| ------------------------- |
| |element2 | |
| ------------------------- |
| |
-----------------------------------
这两个元素都绑定了click事件,如果用户点击element2,那个先触发呢,换句话说事件触发的的顺序是怎样的呢?
- 网景公司说element1优先,这叫事件捕获(event capturing)
- 微软则坚持element2优先,这叫事件冒泡(event bubbling)
首先来看看事件捕获:
| |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------
可以看出element1上的事件处理函数先触发,element2上的事件处理函数后触发。
那么事件冒泡又是怎样的呢:
/ \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------
这种情况下element2上面的事件处理函数先触发,element1上面的事件处理函数后触发。
对于这两种模型的截然不同,W3C很巧妙地在这场对抗中保持中立:任何W3C事件模型中发生的事件都是先捕获,直到它到达目标元素,然后再向外冒泡。
| | / \
-----------------| |--| |-----------------
| element1 | | | | |
| -------------| |--| |----------- |
| |element2 \ / | | | |
| -------------------------------- |
| W3C event model |
------------------------------------------
基于事件模型可以有很多应用,最常见的就是事件代理和委托,感兴趣的可以深入研究,这里我不在具体描述。
普通事件与事件绑定
普通事件就是on+event
绑定的事件,Javascript中有很多定义好的事件,例如 onclick
, onkeyup
, onmouseup
等,这种方式的使用示例如下:
javascript
obj1.onclick = function1; obj1.onclick = function2;
以上的操作下,function1会被function2覆盖而只执行function2,解除事件只需:
javascript
obj1.onclick = null;
使用支持W3C标准的浏览器中绑定事件用的是addEventListener
:
javascript
obj1.addEventListener("click",change1,false); obj1.addEventListener("click",change2,false);
事件执行顺序跟绑定顺序一样,先执行change1,再执行change2,解除绑定:
javascript
obj1.removeEventListener("click",change1,false);
在IE里面,绑定事件要用attachEvent
:
javascript
obj1.attachEvent("onclick",change1); obj1.attachEvent("onclick",change2);
绑定时事件名称同样要以on为前缀,而且没有后面是否冒泡的boolean值,但是这种执行顺序变成了倒序,先执行change2,再执行change1。 事件取消绑定:
javascript
obj1.detachEvent("onclick",change1);
stopPropagation,preventDefault和return false
因为有父, 子节点同在, 因为有监听事件和浏览器默认动作之分. 使用 JavaScript 时为了达到预期效果经常需要阻止事件和动作执行. 一般我们会用到三种方法, 分别是 stopPropagation()
, preventDefault()
和 return false
。那么他们有什么区别呢?
See the Pen stopPropagation,preventDefault和return false对比 by superlin (@superlin) on CodePen.
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>stopPropagation:因为事件可以在各层级的节点中传递, 不管是冒泡还是捕获, 有时我们希望事件在特定节点执行完之后不再传递, 可以使用事件对象的 stopPropagation
方法。
preventDefault:元素上带有的功能. 如: 点击 a 链接节点的跳转动作, 点击submit按钮表单会提交等,如果监听这些元素的事件时不希望默认动作方式,就可以使用 preventDefault
方法。
return false:退出执行, return false
之后的所有触发事件和动作都不会被执行. 有时候 return false
可以用来替代 stopPropagation
和 preventDefault
,除此之外,还可以返回对象, 跳出循环等。
可以去上面的例子试试哦。
target与currentTarget
target
在事件流的目标阶段;currentTarget
在事件流的捕获,目标及冒泡阶段。只有当事件流处在目标阶段的时候,两个的指向才是一样的, 而当处于捕获和冒泡阶段的时候,target
指向被单击的对象而currentTarget
指向当前事件活动的对象(一般为父级),具体示例如下。
See the Pen target与currentTarget区别 by superlin (@superlin) on CodePen.
<script async src="//assets.codepen.io/assets/embed/ei.js"></script>更多的例子和意见请给我留言。
欢迎光临小弟博客:Superlin's Blog
我的博客原文:DOM中的各种区别小节
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。