DOM常见题目

164 阅读1分钟

一、事件模型

  1. 概念:在DOM中触发事件,事件会经历从上到下的捕获阶段,然后在从下往上的冒泡阶段执行。

    冒泡:当给父子元素的绑定同一事件的时候,触发子元素身上的事件,执行完毕之后,也会触发父级元素相同的事件,这种传播机制叫事件冒泡。

    捕获:给父子元素绑定同一事件时,当触发子元素身上的事件时,先触发父元素,然后再传递给子元素,这种传播机制叫事件捕获;

  2. 实现:

    addEventListener(event, callback, options)
    // options
    [bool] true:在捕获阶段执行
    [bool] false/空:在冒泡阶段执行
    [object] {}: {capture: true, once: true, ...}
    

    可以用event.stopPropagation()来阻止冒泡或捕获(传播)

二、事件委托

  1. 概念:事件委托,就是把原本加在子元素的事件绑定在父元素身上,通过事件冒泡的机制,使子元素能够触发绑定在父元素身上的事件

  2. 实现:

    基础版:

    ul.addEventListener('click', function(e){
        // e.currentTarget 被监听的对象,一般不变
        // e.target 正在操作的对象,有可能变
        if(e.target.tagName.toLowerCase()=== 'li'){
            fn();
        }
    })
    

    进阶版:

    function delegate(element, eventType, selector, fn){
        element.addEventListener(eventType, e =>{
            let el = e.target;
            
            while(!el.matches(selector)){
                if(element === el){
                    el = null;
                    break;
                }
                el = el.parentNode;   
            }
            el && fn.call(el, e)
        })
        
        return element;
    }
    
  3. 优点/解决问题:

    • 节省监听函数
    • 动态监听
  1. 缺点:

    • 调试比较复杂,不容易确定监听者

三、手写一个可拖拽的div

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>JS Bin</title>
    <style>
        #box {
            position: absolute;
            top: 0;
            width: 100px;
            height: 100px;
            border: 1px solid red;

        }
    </style>
</head>

<body>
    <div id="box"> </div>
    <script>
        let position = [];
        let dragging = false;
        let box = document.getElementById('box');

        box.addEventListener('mousedown', function (e) {
            dragging = true;
            position = [e.clientX, e.clientY];
        })

        document.addEventListener('mouseover', function (e) {
            if (!dragging) return;

            const x = e.clientX;
            const y = e.clientY;

            const deltaX = x - position[0];
            const deltaY = y - position[1];

            const left = parseInt(box.style.left || 0);
            const top = parseInt(box.style.top || 0);

            box.style.left = left + deltaX + 'px';
            box.style.top = top + deltaY + 'px';

            position = [x, y];
        })

        document.addEventListener('mouseup', function (e) {
            dragging = false;
        })

    </script>
</body>

</html>