js中的事件,冒泡与捕获

72 阅读1分钟

事件的传播

    //  在当前案例中,点击了box2 的区域 相当于点击了 box1 内部的空间

    //  在触发子元素的事件时,会将 行为 传播给父级的同类型事件
    //  触发了子元素的点击事件时,会将该行为传播给父级
    //  并 触发父级的同类型事件

    //  在传递行为时,会将行为一直向上传递,如果父级有同类型事件,那么触发该事件
    //  如果没有,则继续往上传递
    //  阻止事件传播:stopPropagation

    <div id="box1">
        <div id="box2"></div>
    </div>

    var box1 = document.getElementById('box1')
    var box2 = document.getElementById('box2')
    var Body = document.body

    box1.onclick = function (e) {
        e.stopPropagation()          //阻止事件传播(body不再传播)
        console.log('点击了box1')
    }

    box2.onclick = function () {
        console.log('点击了box2')
    }

    // box1.oncontextmenu = function () {
    //     console.log('右击了box1')
    // }

    Body.onclick = function () {
        console.log('点击了body')
    }

冒泡; 捕获; 目标

<div id="box1">
     <div id="box2"></div>
</div>  

<script>
    // 冒泡:事件传播时,从目标开始传播,一直到父级,body...window
    // 捕获:从最顶层开始,逐层向下传递,一直到目标
    var box1 = document.getElementById('box1')
    var box2 = document.getElementById('box2')
    var Body = document.body

    // 捕获的话 需要 传递 第三个参数 为 true
    // addEventListener 第三个参数 默认值为 false 代表传播方式为冒泡
    // 如果想改变传播方式为 捕获,那么需要 将第三个参数传递为true

    box1.addEventListener('click' , function () {
        console.log('点击了box1')
    },true)

    box2.addEventListener('click' , function () {
        console.log('点击了box2')
    },true)

    Body.addEventListener('click' , function () {
        console.log('点击了body')
    },true)
    
</script>

事件委托

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>

<script>
    var oUl = document.querySelector('ul')
    var oLi = [...document.querySelectorAll('li')]

    // 创建一个li节点
    var newLi = document.createElement('li')
    newLi.innerText = '我是JS创建的'
    oUl.appendChild(newLi)


    oUl.onclick = function (e) {
        // console.log(e.target.nodeName)
        if(e.target.nodeName === 'LI') {
            console.log('点击了li')
        }
    }

    /**
     *  事件委托
     *      因为事件冒泡的存在, 所以点击子元素时, 一定会触发给父级
     * 
     *      所以可以将 子元素统一的事件, 都提交给 父级
     * 
     *  e.target: 触发事件的事件源
     * 
     * 
     * 总结:
     *      为什么要用事件委托
     *          动态的添加了 li 时, 新加的li没有绑定上事件, 需要动态添加完成后重新绑定事件, 这样操作比较麻烦
     *          所以此时可以利用 事件委托
     * 
     *      li 的点击事件必须委托给父级的 点击事件
    */
</script>

默认行为

<a href="xxx">xxxxxx</a>

<script>
    var a = document.querySelector('a')
    a.onclick = function (e) {

        // 1. 方式1
        // console.log('点击了 a 标签, 但是因为有 return false 所以默认的跳转功能被拦截')
        // return false

        // 2. 通过事件对象拦截      preventDefault()    拦截之后, 取消了 a标签的默认跳转功能
        e.preventDefault()
    }
</script>