DOM事件机制

本文详细介绍了JavaScript中HTML事件的工作原理,包括事件源、事件类型和事件处理程序。讨论了事件流的两个阶段:事件冒泡和事件捕获,以及如何阻止事件冒泡。还提到了DOM2级事件的addEventListener方法,支持事件捕获和冒泡模式。此外,文章阐述了事件委托的概念,作为优化页面性能的一种策略,通过将事件处理程序绑定到父元素来管理子元素的事件。
摘要由CSDN通过智能技术生成

      HTML DOM 允许 JavaScript 对 HTML 事件作出反应。JavaScript 能够在事件发生时执行,比如当用户点击某个 HTML 元素时。

       JavaScript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。

事件是由三部分组成

事件源 事件类型 事件处理程序 我们也称为事件三要素

1.事件源:事件被触发的对象 -->按钮对象

2.事件类型:如何触发?触发什么事件?例如鼠标点击,键盘按下等…

3.事件处理程序:通过一个函数赋值的方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
// 事件是由三部分组成

// 事件源 事件类型 事件处理程序 我们也称为事件三要素
// 1.事件源:事件被触发的对象 -->按钮对象
// 2.事件类型:如何触发?触发什么事件?例如鼠标点击,键盘按下等…
// 3.事件处理程序:通过一个函数赋值的方式
        window.onload = function(){
            // 1.获取dom元素
            // 2.给dom元素绑定事件
            // 3.声明事件处理程序
            var div = document.querySelector('div')
            var button = document.querySelector('button')
            // console.log(div, button);//<div> <button onclick="handler()">
            button.onclick = function(){
                div.style.width = '100px'
                div.style.height = '100px'
                div.style.backgroundColor = 'pink'
                div.style.fontSize = '30px'
                div.innerText = 'hello Evan'
            }
            // function handler(){
            //     div.style.width = '100px'
            //     div.style.height = '100px'
            //     div.style.backgroundColor = '100px'
            //     div.style.fontSize = '30px'
            //     div.innerText = 'hello Evan'
            // }   会报错
        }
    </script>
</head>
<body>
    <div>我是div</div>
    <!-- handler()事件处理程序 -->
    <button onclick="handler()">点击我</button>
</body>
</html>
执行事件的步骤

1.获取事件源

2.注册事件(绑定事件)

3.采用函数赋值形式添加事件处理程序

常用事件:
  • 当用户点击鼠标时

  • 当网页加载后

  • 当图像加载后

  • 当鼠标移至元素上时

  • 当输入字段被改变时

  • 当 HTML 表单被提交时

  • 当用户敲击按键时

一.事件流 

事件流描述了页面接收事件的顺序。

1.事件冒泡(IE事件流)

事件冒泡:事件从内向外触发

       IE 事件流被称为事件冒泡,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。

阻止事件冒泡

        使用阻止事件冒泡之前,先要知道DOM事件默认提供的一个对象,HTML DOM Event对象。

         Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。

       事件通常与函数结合使用,函数不会在事件发生前被执行!

      event.stopPropagation()

       直接在对应方法中使用event.stopPropagation()便可阻止事件冒泡。

注意:如果点击方法时需要同时传递其他参数和event,直接传递event这个单词即可
onclick="test(123,event)"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .outer{
            width: 300px;
            height: 300px;
            background-color: skyblue;
            margin: 0 auto;
            padding: 50px;
            box-sizing: border-box;
        }
        .center{
            width: 200px;
            height: 200px;
            background-color: pink;
            padding: 50px;
            box-sizing: border-box;
        }
        .inner{
            width: 100px;
            height: 100px;
            background-image: linear-gradient(to right, hotpink, orange,  blue);
        }
    </style>
    <script>
        // 事件流描述了页面接收事件的顺序。
        
        window.onload = function(){
            // 给dom元素绑定事件
            // 1.获取dom元素
            // 2.给dom绑定事件
            var outer = document.querySelector('.outer')
            var center = document.querySelector('.center')
            var inner = document.querySelector('.inner')
            outer.onclick = function(){
                alert('我是outer')
                console.log(event.target, '触发事件目标源3');
                console.log(event.currentTarget, '当前正在执行事件的dom元素3');
              //  <div class="inner">触发事件目标源3 
                // <div class="outer"> 当前正在执行事件的dom元素3
            }
            center.onclick = function(){
                alert('我是center')
                // event.stopPropagation(); // 运行到center停
                console.log(event.target, '触发事件目标源2');
                console.log(event.currentTarget, '当前正在执行事件的dom元素2');
               //<div class="inner">触发事件目标源2 
                // <div class="center"> 当前正在执行事件的dom元素2
            }
            inner.onclick = function(){
                alert('我是inner')
                // 阻止事件冒泡 event 表示当前事件对象
//                 console.log(event, '事件对象');
 click { target: div.inner, buttons: 0, clientX: 994, clientY: 144, layerX: 994, layerY: 144 }

                // event.stopPropagation()  //只运行inner

                // target 指向事件触发目标源 谁触发的事件 target就是谁
                // currentTarget 当前正在执行事件的dom元素 谁正在执行 currentTarget 就是谁
                console.log(event.target, '触发事件目标源1');
                console.log(event.currentTarget, '当前正在执行事件的dom元素1');
              // <div class="inner">触发事件目标源1 
                // <div class="inner"> 当前正在执行事件的dom元素1
            }
        }
    </script>
</head>
<body>
    <!-- 事件流:描述了页面接收事件的顺序 -->
    <!-- 1.事件冒泡 -->
    <!-- 2.事件捕获 -->
    <!--
		事件流:描述的是页面接受事件的顺序
		分为事件冒泡和事件捕获
		事件冒泡:事件从内向外触发
		事件捕获:事件从外向内触发
		事件流机制:事件捕获--到达目标--事件冒泡
    --> 
    <div class="outer">
        <div class="center">
            <div class="inner"></div>
        </div>
    </div>
</body>
</html>

2.dom0级事件和dom2级事件 

dom0级事件绑定 on事件类型  dom0级不可以追加同一类型事件 追加执行最后一次事件处理程序

dom2级事件 addEventListener('事件类型', 事件处理程序, true/false)

        true表示执行事件捕获 false表示执行事件冒泡(默认值)

dom2级事件事件可以追加事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        window.onload = function(){
            var btn = document.querySelector('button')
            // dom0级事件绑定 on事件类型 dom0级事件不可以追加同一类型事件 追加执行最后一次事件处理程序
            // 绑定第一个事件
            btn.onclick = function(){
                console.log(this);//<button>
            }
            // 追加事件
            btn.onclick = function(){
                alert('第二次事件')
            }
            // dom0事件解绑  绑定解绑都是重新赋值的操作
            btn.onclick = null


            // dom2级事件 addEventListener('事件类型', 事件处理程序, true/false)
            // true表示执行事件捕获 false表示执行事件冒泡
            // dom2级事件事件可以追加事件
            function handler1(){
                console.log(this);
            }
            function handler2(){
                alert('第二次事件')
            }
            btn.addEventListener('click', handler1)
            btn.addEventListener('click', handler2)

            // dom2级事件解绑 removeEventListener('事件类型', 具名函数事件处理程序,)
            // // function add(){} 具名函数
            btn.removeEventListener('click', handler1)


            /**
			 * dom0级和dom2级事件区别?
			 * 1.dom0级绑定事件使用on关键字绑定  解绑on事件类型设置为null
			 * 2.dom2级事件绑定使用addEventListener 解绑使用removeEventListener
			 * 3.dom0级事件不可以追加同一类型事件 追加就是覆盖
			 * 4.dom2级事件可以追加同一类型事件 追加就依次执行
			*/
        }
    </script>
</head>
<body>
    <button>点击我</button>
</body>
</html>

3.事件捕获(Netscape事件流)

事件捕获:事件从外向内触发

       Netscape Communicator 团队提出了另一种名为事件捕获的事件流。事件捕获的意思是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。事件捕获实际上是为了在事件到达最终目标前拦截事件。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .outer{
            width: 300px;
            height: 300px;
            background-image: radial-gradient(hotpink, skyblue, orange);
            margin: 0 auto;
            padding: 50px;
            box-sizing: border-box;
        }
        .center{
            width: 200px;
            height: 200px;
            background-color: pink;
            padding: 50px;
            box-sizing: border-box;
        }
        .inner{
            width: 100px;
            height: 100px;
            background-image: linear-gradient(to right, hotpink, orange,  blue);
        }
    </style>
    <script>
        window.onload = function(){
            var outer = document.querySelector('.outer')
            var center = document.querySelector('.center')
            var inner = document.querySelector('.inner')
            function handler1(){
                console.log('outer');
            }
            function handler2(){
                console.log('center');
            }
            function handler3(){
                console.log('inner');
            }
            // dom2级事件 addEventListener('事件类型', 事件处理程序, true/false)
            // true表示执行事件捕获(由外向内) false表示执行事件冒泡(默认)(由内向外)
            outer.addEventListener('click', handler1, true)
            center.addEventListener('click', handler2, true)
            inner.addEventListener('click', handler3, true)
        }
    </script>
</head>
<body>
    <div class="outer">
        <div class="center">
            <div class="inner"></div>
        </div>
    </div>
</body>
</html>

4.DOM事件流

事件流机制:事件捕获--到达目标--事件冒泡

        DOM2 Events 规范规定事件流分为 3 个阶段:事件捕获、到达目标和事件冒泡。事件捕获最先发生,为提前拦截事件提供了可能。然后,实际的目标元素接收到事件。最后一个阶段是冒泡,最迟要在这个阶段响应事件。  

注意:所有现代浏览器都支持 DOM 事件流,只有 IE8 及更早版本不支持。

 二.阻止事件默认行为

preventDefault()方法

       用于阻止特定事件的默认动作。比如,链接的默认行为就是在被单击时导航到 href 属性指定的 URL或是修改表单提交的默认事件。如果想阻止这些行为,可以在 onclick 事件处理程序中取消

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<script>
		window.onload = function(){
			var input = document.querySelector('input');
			var a = document.querySelector('a');
			input.onclick = function(){
				// 阻止input标签默认提交行为
				event.preventDefault()
			}
			a.onclick = function(){
				// 阻止a标签默认跳转行为
				event.preventDefault()
			}
		}
	</script>
</head>
<body>
	<form action="text.php">
		<input type="submit" value="提交">
	</form>
	<a href="https:///www.baidu.com">跳转到百度</a>
</body>
</html>

三.事件委托

       在 JavaScript 中,页面中事件处理程序的数量与页面整体性能直接相关。原因有很多。首先,每个函数都是对象,都占用内存空间,对象越多,性能越差。其次,为指定事件处理程序所需访问 DOM 的次数会先期造成整个页面交互的延迟。只要在使用事件处理程序时多注意一些方法,就可以改善页面性能。

        事件委托就是当事件触发时,把要做的事委托给父元素(或父元素的父元素)来处理。也就是:利用冒泡的原理,把事件加到父级上,通过判断事件来源的子集,执行相应的操作。使用事件委托技术能让你避免对特定的每个节点添加事件监听器。

       事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件。例如,click 事件冒泡到 document。这意味着可以为整个页面指定一个 onclick 事件处理程序,而不用为每个可点击元素分别指定事件处理程序。

事件委托(事件代理) 

        原理:利用事件冒泡 只指定一个事件处理程序 就可以管理某一类型的事件

                        将本应该绑定给子元素事件绑定给父元素

        目的:优化页面性能 减少事件的执行 减少浏览器的重排(回流)和重绘 给新增的元素绑定事件

<一>给所有li绑定事件 点击的时候背景色变成红色 

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<script>
		window.onload = function(){
			var ul = document.querySelector('ul');
			// 给所有li绑定事件 点击的时候背景色变成红色 
			var lis = document.querySelectorAll('li');
			for(var i=0;i<lis.length;i++){
				lis[i].onclick = function(){
					this.style.backgroundColor = 'red'
				}
			}
			var newLi = document.createElement('li');
			newLi.innerText ='第11个li'
			ul.appendChild(newLi);
			
		}
	</script>
</head>
<body>
	 <ul>
		<li>第1个li</li>
		<li>第2个li</li>
		<li>第3个li</li>
		<li>第4个li</li>
		<li>第5个li</li>
		<li>第6个li</li>
		<li>第7个li</li>
		<li>第8个li</li>
		<li>第9个li</li>
		<li>第10个li</li>
	 </ul>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<script>
		window.onload = function(){
			var ul = document.querySelector('ul');
			// 给所有li绑定事件 点击的时候背景色变成红色 
			var lis = document.querySelectorAll('li');
			// for(var i=0;i<lis.length;i++){
			// 	lis[i].onclick = function(){
			// 		this.style.backgroundColor = 'red'
			// 	}
			// }
			var newLi = document.createElement('li');
			newLi.innerText ='第11个li'
			ul.appendChild(newLi);
			/**
			 * 事件委托 将子元素事件代理给父元素 只绑定一次事件 管理一类事件
			*/
			ul.onclick = function(){
				// event 事件对象 event.target 
				// event.target.style.backgroundColor = 'red'
				var target = event.target;
				if(target.tagName === 'LI'){
					target.style.backgroundColor = 'red'
				}
			}
		}
	</script>
</head>
<body>
	<!-- 
		事件委托(事件代理) *****
			原理:利用事件冒泡 只指定一个事件处理程序 就可以管理某一类型的事件
			将本应该绑定给子元素事件绑定给父元素
			目的:优化页面性能 减少事件的执行 减少浏览器的重排(回流)和重绘 给新增的元素绑定事件
	 -->
	 <ul>
		<li>第1个li</li>
		<li>第2个li</li>
		<li>第3个li</li>
		<li>第4个li</li>
		<li>第5个li</li>
		<li>第6个li</li>
		<li>第7个li</li>
		<li>第8个li</li>
		<li>第9个li</li>
		<li>第10个li</li>
	 </ul>
</body>
</html>

 <二>点击不同li内部内容 发生不同改变

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<script>
		window.onload = function(){
			var ul = document.querySelector('ul');
			// 点击不同li内部内容 发生不同改变
			var item1 = document.querySelector('#frist');
			var item2 = document.querySelector('#second');
			var item3 = document.querySelector('#three');
			item1.onclick = function(){
				this.innerText = 'hello html'
			}
			item2.onclick = function(){
				this.innerText = 'hello css'
			}
			item3.onclick = function(){
				this.innerText = 'hello js'
			}
		}
	</script>
</head>
<body>
	<ul>
		<li id="frist">li标签</li>
		<li id="second">li标签</li>
		<li id="three">li标签</li>
	</ul>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<script>
		window.onload = function(){
			var ul = document.querySelector('ul');
			// 点击不同li内部内容 发生不同改变
			ul.onclick = function(){
				var target = event.target;
				console.log(target);
				// <li id="frist">
				// <li id="second">
				// <li id="three">
				switch(target.id){
					case 'frist':
						target.innerText = 'hello html';
						break;
					case 'second':
						target.innerText = 'hello css';
						break;
					case 'three':
						target.innerText = 'hello js';
						break;
					default:
						target.innerText = '我是li标签'
				}
			}
		}
	</script>
</head>
<body>
	<ul>
		<li id="frist">li标签</li>
		<li id="second">li标签</li>
		<li id="three">li标签</li>
	</ul>
</body>
</html>

四.事件类型

<一>用户界面事件(UIEvent):涉及与 BOM 交互的通用浏览器事件。

 1.select  绑定选择事件 在文本框(<input>或 textarea)上当用户选择了一个或多个字符时触发。

var input = document.querySelector('input');
		
    input.onselect = function(){
		console.log('我被选择了');
		// 通过window.getSelection()获取到选中的部分
		console.log(window.getSelection().toString());
		}

 2.resize 方法 窗口进行缩放时候触发

document.body.onresize = function(){
	console.log(window.outerHeight,window.outerWidth)//942 1187
}

3.scroll 事件 绑定滚动事件

var div = document.querySelector('div');
	div.onscroll = function(){
	console.log('我在滚动')
}

 4.load

       在 window 上当页面加载完成后触发,在窗套(<frameset>)上当所有窗格(<frame>)都加载完成后触发,在<img>元素上当图片加载完成后触发,在<object>元素上当相应对象加载完成后触发。

<script>
  window.onload = function () {
    console.log('onload');
  }
</script>

5.unload

       当页面完全卸载后在window上触发,当所有框架都卸载后在框架集上触发,当嵌入的内容卸载完毕后在<object>上触发。

<二>焦点事件(FocusEvent):在元素获得和失去焦点时触发。

聚焦focus 失焦 blur

input.onfocus  = function(){
	this.style.backgroundColor = 'pink'
}
input.onblur = function(){
	console.log('请单击输入框')
}
focusin

当元素获得焦点时触发。这个事件是 focus 的冒泡版。

focusout

当元素失去焦点时触发。这个事件是 blur 的冒泡版。

<三>鼠标事件(MouseEvent):使用鼠标在页面上执行某些操作时触发。

 1.双击 dbclick

div.ondblclick = function(){
	console.log('我被双击了')
}

2.鼠标移入mouseenter 鼠标移除mouseleave 鼠标一直移动mousemove

div.onmouseenter = function(){
	console.log('鼠标移入')
}
div.onmouseleave = function(){
	console.log('鼠标移出')
}
div.onmousemove = function(){
	console.log('鼠标一直在移动')
}
  • click

    在用户单击鼠标主键(通常是左键)或按键盘回车键时触发。这主要是基于无障碍的考虑,让键盘和鼠标都可以触发 onclick 事件处理程序。

  • dblclick

    在用户双击鼠标主键(通常是左键)时触发。这个事件不是在 DOM2 Events 中定义的,但得到了很好的支持,DOM3 Events 将其进行了标准化。

  • mousedown

    在用户按下任意鼠标键时触发。这个事件不能通过键盘触发。

  • mouseenter

    在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。mouseenter 事件不是在 DOM2 Events 中定义的,而是 DOM3 Events中新增的事件。

  • mouseleave

    在用户把鼠标光标从元素内部移到元素外部时触发。这个事件不冒泡,也不会在光标经过后代元素时触发。mouseleave 事件不是在 DOM2 Events 中定义的,而是 DOM3 Events中新增的事件。

  • mousemove

    在鼠标光标在元素上移动时反复触发。这个事件不能通过键盘触发。

  • mouseout

    在用户把鼠标光标从一个元素移到另一个元素上时触发。移到的元素可以是原始元素的外部元素,也可以是原始元素的子元素。这个事件不能通过键盘触发。

  • mouseover

    在用户把鼠标光标从元素外部移到元素内部时触发。这个事件不能通过键盘触发。

  • mouseup

    在用户释放鼠标键时触发。这个事件不能通过键盘触发。

3.滚轮事件(WheelEvent):使用鼠标滚轮(或类似设备)时触发。

        mousewheel  鼠标滚轮事件

4.键盘事件(KeyboardEvent):使用键盘在页面上执行某些操作时触发。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<script>
		window.onload = function(){
			var input = document.querySelector('input');
			//键盘按下事件 keydown 按键 keyCode
			input.onkeydown = function(){
				console.log(event.keyCode)
			}
			// 键盘抬起事件 keyup 
			input.onkeyup = function(){
				console.log('我被抬起了')
			}
			// 键盘持续按下事件 
			input.onkeypress=function(){
				console.log('持续按下')
			}
			//输入框输入事件 获取文本输入值
			input.addEventListener('textInput',function(event){
				console.log(event.data)
			});
		}
	</script>
</head>
<body>
	<input type="text">
</body>
</html>

5.输入事件(InputEvent):向文档中输入文本时触发。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值