js事件、事件冒泡与事件委托(事件代理)

js事件是js中非常重要的知识点。js与用户的很多互动都需要事件来完成。比如:
1、点击登录按钮完成登录的click点击事件
2、输入框失焦校验的blur失焦事件
3、鼠标移入移出的mouseover和mouseout事件等等。
下面通过代码来展示在dom元素上绑定一个点击事件

	<body>
		<input type='button' value="请点击!" onClick="clickHandler">
		<script>
			function clickHandler(){
				console.log('clicked')
			}
		</script>
	</body>

第二种绑定事件的方式是听过js事件监听来给元素注册事件:

	<body>
		<input id="input" type='button' value="请点击!">
		<script>
			var input = document.getElementById('input')
			input.addEventListener('click',()=>{
				console.log('clicked')
			})
		</script>
	</body>

两种方法都很简单,值得小心的是,以点击事件为例:在dom中直接绑定事件,用的是onClick属性,而js绑定事件是click,没有on

常见的js事件有:

1)、onClick点击事件
2)、onFous获得焦点和onBlur失去焦点事件
3)、onMouseover和onMouseout事件
4)、onKeyDown和onKeyUp事件
更多事件可自行查阅api文档

那什么是事件冒泡呢?

下面还是通过代码来演示:

	<body>
		<div id="div1">
        <p id="p1">第一个p</p>
        <p>第二个p</p>
        <p>第三个p</p>
        <p>第四个p</p>
        <p>第五个p</p>
    </div>
    <script>
    // 这里为了方便给元素注册事件,简单封装了一个添加事件监听的函数
		function addEvent(ele,eventType,callback){
            ele.addEventListener(eventType,callback)
        }
        var div1 = document.getElementById('div1')
        var pList = document.getElementsByTagName('p')
        // 循环为每个p注册点击事件
        for(let i = 0;i<pList.length;i++){
            addEvent(pList[i],'click',event=>{
                console.log(`第:${i}个p标签被点击了`)
            })
        }
        // 为p的父元素div1注册点击事件监听
        addEvent(div1,'click',event=>{
            console.log('div1 =====>clicked'+'====target===>'+event.target)
        })
        // 为body注册点击事件
        addEvent(document.body,'click',event=>{
            console.log('body*****clicked****target*****'+event.target)
        })
	</script>
	</body>

当我们点击任意的p元素时,输出结果如下:
js事件、事件冒泡与事件委托(事件代理)_第1张图片
可以看到,当点击第二个p时,不仅触发了p本身的点击事件,还触发了p的父元素div1和div1的父元素body的点击事件,示意图如下:
js事件、事件冒泡与事件委托(事件代理)_第2张图片
如果我们想阻止事件冒泡呢,只需要在当前目标上加上该方法: event.stopPropagation()
js事件、事件冒泡与事件委托(事件代理)_第3张图片
此时对比代码执行结果:
js事件、事件冒泡与事件委托(事件代理)_第4张图片
此时,div1和body的点击事件没有被触发。

什么又是事件委托呢??

事件委托主要利用的是事件冒泡机制,通过事件传递,把本应该绑定在子元素上的事件,绑定到父元素中,但是父元素中这么多子元素,怎么区分是哪一个呢? 主要是通过event.target属性来获取当前触发事件的子元素,下面以代码为例:

	<body>
    <div id="div1">
        <p>第一个p标签</p>
        <p>第二个p标签</p>
        <p>第三个p标签</p>
        <p>第四个p标签</p>
        <p>第五个p标签</p>
        <p>第六个p标签</p>
    </div>
    <script>
        var div1 = document.getElementById('div1')
        div1.addEventListener('click',(event)=>{
        	// 获取当前实际触发的元素
            var target = event.target
            alert(target.innerHTML)
        })
    </script>
</body>

面试题:封装一个公共函数,用于事件监听:

	<body>
    	<div id="div1">
        <p>这是p1</p>
        <p>这是p2</p>
        <p>这是p3</p>
        <p>这是p4</p>
        <p>这是p5</p>
        <p>这是p6</p>
        <p>这是p7</p>
        <p>这是p8</p>
        <p>这是p9</p>
    </div> 
    <script>
    	/**
         * @description: 封装的公共的函数
         * @param {elem}:dom元素,给哪个dom元素添加事件
         * @param {type}:事件类型
         * @param {selecter}:选择器,根据这个参数判断是否需要事件代理
         * @param {fn}:执行函数 
         * @return: 
         */
        function bindEvent(elem, type, selecter, fn) {
            if (fn == null) {
                //判断一下selecter这个参数是否存在
                fn = selecter
                selecter = null
            }
            elem.addEventListener(type, function (e) {
                //代理
                if (selecter) {
                    //代理
                    var target = e.target
                    if (target.matches(selecter)) {
                    //这里target代表出发事件的节点,是否和你传的selecter相匹配
                        fn.call(target, e)
                    }
                } else {
                    //  普通注册
                    fn.call(target,e)
                }
            })
        }

        var div1 = document.getElementById('div1')
        // 注意,这里的函数不能使用箭头函数,箭头函数没有this指向,会向上找到window
        bindEvent(div1,'click','p',function(e){
            e.preventDefault()
            console.log(this.innerHTML)
        })
    </script>
</body>

关于target.matches()用法参考:Element.matches()用法

你可能感兴趣的:(js事件、事件冒泡与事件委托(事件代理))