# 5.3 DOM 相关

1. `document.getElementById('a')` 通过 id 值为 a 获取页面中的一个元素
2. `document.getElementsByName('na')` 通过 name 属性值为 na 获取页面中的一个元素
3. `document.getElementsByTagName('div')` 通过标签名获取所有 div
4. 以上说法都不对

<details>

<summary>关于获取页面元素，以上说法正确的是</summary>

答案：1 和 3

1. `document.getElementById()`
2. `document.getElementsByClassName()`
3. `document.getElementsByName()` 给出的 attribute name
4. `document.getElementsByTagName()`
5. `document.getElementsByTagNameNS()`

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FPXnUwgF0TZkhL4qWwE13%2Fimage.png?alt=media\&token=ec665f3b-4031-46ba-9cc4-f5dba696eb02)

</details>

<details>

<summary>事件流</summary>

HTML 与 JavaScript 交互是通过“事件驱动”来实现的，比如鼠标点击事件 onclick、页面的滚动事件 onscroll。我们可以向文档或文档中的元素，添加事件侦听器来监听特定的事件。

“事件流”描述的是，从页面中接收事件的顺序。DOM2 级事件流包括下面几个阶段：

1. 事件捕获阶段
2. 处于目标阶段
3. 事件冒泡阶段

addEventListener 是 DOM2 级事件新增的指定事件处理程序的操作，该方法接收三个参数：

1. 要处理的事件名
2. 作为事件处理程序的函数
3. 一个布尔值
   * true 表示是在捕获阶段调用事件处理程序
   * false 表示在冒泡阶段调用事件处理程序

IE 只支持事件冒泡。

事件代理在捕获阶段的实际应用：

* 在父元素层面阻止事件向子元素传播
* 代替子元素执行某些操作

</details>

<details>

<summary>如何让事件先冒泡后捕获？</summary>

在 DOM 标准事件模型中，是先捕获后冒泡。

但是如果要实现先冒泡后捕获的效果，对于同一个事件，监听捕获和冒泡，分别对应相应的处理函数，监听到捕获事件，先暂缓执行，直到冒泡事件被捕获后再执行捕获之间。

</details>

<details>

<summary>事件委托（事件代理）</summary>

事件委托本质上是利用了浏览器的事件冒泡的机制。

事件通过冒泡传到父节点，然后父节点通过事件对象来获取目标节点。这样就可以由父节点的监听函数统一处理多个子元素的事件，这种方式也叫事件代理。

好处：

* 不需要给每一个元素都绑定一个监听事件，从而减少了内存上的消耗
* 还可以实现事件的动态绑定，比如新增了子节点

事件冒泡，就是元素自身的事件被触发后，如果父元素有相同的事件，如 onclick 事件， 那么元素本身的触发状态就会传递——冒到父元素，父元素的相同事件也会一级一 级根据嵌套关系向外触发，直到 document/window，冒泡过程结束。

</details>

<details>

<summary>addEventListener 参数</summary>

```javascript
addEventListener(type, listener)
addEventListener(type, listener, options)
addEventListener(type, listener, useCapture)
```

1. `event` 事件名
2. `function` 事件触发时执行的函数
3. `useCapture` 布尔值，默认是 `false`，表示事件是捕获还是冒泡
   * 在冒泡中，内部元素先被触发，然后再触发外部元素
   * 捕获中，外部元素先被触发，在触发内部元素

</details>

<details>

<summary>节流和防抖</summary>

详见 <http://www.cnblogs.com/coco1s/p/5499469.html>

</details>

<details>

<summary>requestAnimationFrame</summary>

详见 <http://www.cnblogs.com/xiaohuochai/p/5777186.html>

</details>

<details>

<summary>mouseover 和 mouseenter 的区别</summary>

* mouseover：当鼠标移入元素或其子元素都会触发事件，所以有一个重复触发，冒泡的过程。对应的移除事件是 mouseout
* mouseenter：当鼠标移出元素本身（不包含元素的子元素）会触发事件，也就是不会冒泡。对应的移除事件是 mouseleav

</details>

<details>

<summary>各种位置</summary>

1. clientHeight：表示的是可视区域的高度，不包含 border 和滚动条
2. offsetHeight：表示可视区域的高度，包含了 border 和滚动条
3. scrollHeight：表示了所有区域的高度，包含了因为滚动被隐藏的部分
4. clientTop：表示边框 border 的厚度，在未指定的情况下一般为 0
5. scrollTop：滚动后被隐藏的高度，获取对象相对于由 offsetParent 属性指定的父坐标(css 定位的元素或 body 元素)距离顶端的高度
6. offsetTop

</details>

<details>

<summary>移动端 click 的 300ms 延迟</summary>

click 在 ios 上有 300ms 延迟，原因及如何解决？

（1）粗暴型，禁用缩放

```html
<meta name="viewport" content="width=device-width, user-scalable=no">
```

（2）利用 FastClick，原理是：检测到 touchend 事件后，立刻触发模拟 click 事件，并且把浏览器 300 毫秒之后真正触发的事件给阻断掉

</details>

<details>

<summary>加载图片</summary>

```html
<div id="mypic">onloading......</div>
<script type="text/javascript">
    var obj=new Image();
    obj.src = "xxx.jpg";

    function show(){
        alert('图片的宽度为:'+obj.width+';图片的高度为:'+obj.height)
        document.getElementById("mypic").innnerHTML="<img src='"+this.src+"' />"
    }

    // 方法一
    obj.onload = function(){ 
        show()
    }
    // 方法二
    obj.onreadystatechange=function(){
        if(this.readyState=="complete"){
            show()
        }
    }
</script>
```

</details>

<details>

<summary>HTML5 drag API</summary>

1. `dragstart`
2. `darg`
3. `dragenter`
4. `dragover`
5. `dragleave`
6. `drop`
7. `dragend`

</details>

<details>

<summary>实现拖拽</summary>

首先是三个事件，分别是 mousedown，mousemove，mouseup。

当点击鼠标时，需要一个 tag 标识此时已经按下，可以执行 mousemove 里面的具体方法。

clientX，clientY 标识的是鼠标的坐标，分别标识横坐标和纵坐标。用 offsetX 和 offsetY 来表示元素的初始坐标。

* 移动的距离=鼠标移动时候的坐标-鼠标按下去时候的坐标
* 定位信息 = 鼠标移动时候的坐标-鼠标按下去时候的坐标+元素初始情况下的 offetLeft

还有一点也是原理性的东西，也就是拖拽的同时是绝对定位，我们改变的是绝对定位条件下的 left 以及 top 等值。

补充：也可以通过 HTML5 的拖放（Drag 和 drop）来实现

</details>

<details>

<summary>virtual dom</summary>

详见 vue

Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。

</details>
