zoukankan      html  css  js  c++  java
  • js学习(十四)-- 事件

    HTML DOM Event 对象(https://www.w3school.com.cn/jsref/dom_obj_event.asp)

    本节要点记录

    • callback.call(obj)
      callback函数有call和apply方法,可以在执行函数是动态的绑定上下文
      callback.call(obj);就是绑定其上下文为obj
    • 事件对象、
      使用函数汇总传递的事件对象event可以获取target,用来指定事件的绑定对象
      event.target.className == "link";

    1. 事件对象

    事件对象,当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数
    在事件对象中封装了当前事件相关的一切信息。比如,鼠标的坐标、键盘、鼠标滚轮滚动的方向。。。

    • onmousemove
      该事件将会在鼠标在元素中移动时被触发
    areaDiv.onmousemove = function(){}
    
    • clientX可以获取鼠标指针的水平坐标
      clientY可以获取鼠标指针的垂直坐标
    //只需要定义一个形参event就可以使用事件对象了
    areaDiv.onmousemove = function(event){
          /*
          * clientX可以获取鼠标指针的水平坐标
          * clientY可以获取鼠标指针的垂直坐标
          */
          var x = event.clientX;
          var y = event.clientY;
          alert("x = "+x+",Y = "+y);
    }
    

    在IE8中,响应函数被触发时,浏览器不会传递事件对象
    在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的

    window.event.clientX;
    

    火狐没有window.event,IE没有event
    针对火狐和IE做出代码优化

    //只需要定义一个形参event就可以使用事件对象了
    areaDiv.onmousemove = function(event){
          if(!event){
                event = window.event;
          }
          event = event || window.event;//利用了||的短路,如果event为true则直接返回,如果为false就返回后者,是前面代码的改进版
          /*
          * clientX可以获取鼠标指针的水平坐标
          * clientY可以获取鼠标指针的垂直坐标
          */
          var x = event.clientX;
          var y = event.clientY;
          alert("x = "+x+",Y = "+y);
    }
    

    练习--div跟随鼠标移动

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<style type="text/css">
    			#box1{
    				100px;
    				height:100px;
    				background-color:red;
    				/**
    				 * 开启box1的绝对定位
    				 */
    				position:absolute;
    			}
    		</style>
    		<script type="text/javascript">
    			window.onload = function(){
    				/**
    				 * 使div可以跟随鼠标移动
    				 */
    				//获取box1 
    				var box1 = document.getElementById("box1");
    				//绑定鼠标移动事件
    				document.onmousemove = function(event){
    					//解决兼容问题
    					event = event||window.event;
    					//获取到鼠标的坐标
    					/**
    					 * clientX和clientY
    					 *   用于获取鼠标在当前的可见窗口的坐标
    					 * 	div的偏移量,是相对于整个页面的
    					 * pageX和pageY可以获取鼠标相对于当前页面的坐标
    					 * 但是这两个属性在IE8中不支持
    					 */
    					var left = event.pageX;
    					var top = event.pageY;
    					
    					
    					//设置div的偏移量
    					box1.style.left = (left-50)+"px";
    					box1.style.top = (top-50)+"px";
    				}
    			}
    		</script>
    	</head>
    	<body>
    		<div id="box1">
    			
    		</div>
    	</body>
    </html>
    
    

    上述方法使用pageX和pageY不被IE8所支持
    解决方法

    <script type="text/javascript">
    			window.onload = function(){
    				/**
    				 * 使div可以跟随鼠标移动
    				 */
    				//获取box1 
    				var box1 = document.getElementById("box1");
    				//绑定鼠标移动事件
    				document.onmousemove = function(event){
    					//解决兼容问题
    					event = event||window.event;
    					//获取到鼠标的坐标
    					/**
    					 * clientX和clientY
    					 *   用于获取鼠标在当前的可见窗口的坐标
    					 * 	div的偏移量,是相对于整个页面的
    					 */
    					var left = event.clientX;
    					var top = event.clientY;
    					
    					//获取滚动条滚动的距离
    					/**
    					 * chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取
    					 * 火狐等浏览器认为浏览器的滚动条是html的
    					 */
    					//var st = document.body.scrollTop;//火狐不支持
    					//var st = document.documentElement.scrollTop;//chrome不支持 
    					
    					var st = document.body.scrollTop || document.documentElement.scrollTop;
    					var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
    					//设置div的偏移量
    					box1.style.left = (left-50+sl)+"px";
    					box1.style.top = (top-50+st)+"px";
    				}
    			}
    		</script>
    

    2.事件的冒泡(Bubble)

    • 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
    • 在开发中,大部分情况冒泡都是有用的
    • 如果不希望发生事件冒泡可以通过事件对象来取消冒泡
    <script type="text/javascript">
    			window.onload = function(){		
    				/*
    				 * 事件的冒泡(Bubble)
    				 * 	- 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
    				 * 	- 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡
    				 * 
    				 */
    				
    				//为s1绑定一个单击响应函数
    				var s1 = document.getElementById("s1");
    				s1.onclick = function(event){
    					event = event || window.event;
    					alert("我是span的单击响应函数");
    					
    					//取消冒泡
    					//可以将事件对象的cancelBubble设置为true,即可取消冒泡
    					event.cancelBubble = true;
    				};
    				
    				//为box1绑定一个单击响应函数
    				var box1 = document.getElementById("box1");
    				box1.onclick = function(event){
    					event = event || window.event;
    					alert("我是div的单击响应函数");
    					
    					event.cancelBubble = true;
    				};
    				
    				//为body绑定一个单击响应函数
    				document.body.onclick = function(){
    					alert("我是body的单击响应函数");
    				};
    	
    			};
    	
    		</script>
    

    2.1事件的委派(冒泡应用)

    希望只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的
    我们可以尝试将其绑定给元素的共同的祖先元素

    事件的委派

    • 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素,从而通过祖先元素的响应函数来处理事件。
    • 事件委派就是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
    • 使用事件对象可以指定触发的事件对象
    if(event.target.className == "link"){
          alert("hello world!");
    }
    

    事件委派练习

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8" />
    		<title></title>
    		<script type="text/javascript">
    			
    			window.onload = function(){
    				
    				var u1 = document.getElementById("u1");
    				
    				//点击按钮以后添加超链接
    				var btn01 = document.getElementById("btn01");
    				btn01.onclick = function(){
    					//创建一个li
    					var li = document.createElement("li");
    					li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";
    					
    					//将li添加到ul中
    					u1.appendChild(li);
    				};
    				
    				
    				/*
    				 * 为每一个超链接都绑定一个单击响应函数
    				 * 这里我们为每一个超链接都绑定了一个单击响应函数,这种操作比较麻烦,
    				 * 	而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定
    				 */
    				//获取所有的a
    				var allA = document.getElementsByTagName("a");
    				//遍历
    				/*for(var i=0 ; i<allA.length ; i++){
    					allA[i].onclick = function(){
    						alert("我是a的单击响应函数!!!");
    					};
    				}*/
    				
    				/*
    				 * 我们希望,只绑定一次事件,即可应用到多个的元素上,即使元素是后添加的
    				 * 我们可以尝试将其绑定给元素的共同的祖先元素
    				 * 
    				 * 事件的委派
    				 * 	- 指将事件统一绑定给元素的共同的祖先元素,这样当后代元素上的事件触发时,会一直冒泡到祖先元素
    				 * 		从而通过祖先元素的响应函数来处理事件。
    				 *  - 事件委派是利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能
    				 */
    				
    				//为ul绑定一个单击响应函数
    				u1.onclick = function(event){
    					event = event || window.event;
    					
    					/*
    					 * target
    					 * 	- event中的target表示的触发事件的对象
    					 */
    					//alert(event.target);
    					
    					
    					//如果触发事件的对象是我们期望的元素,则执行否则不执行
    					if(event.target.className == "link"){
    						alert("我是ul的单击响应函数");
    					}
    					
    				};
    				
    			};
    			
    		</script>
    	</head>
    	<body>
    		<button id="btn01">添加超链接</button>
    		
    		<ul id="u1" style="background-color: #bfa;">
    			<li>
    				<p>我是p元素</p>
    			</li>
    			<li><a href="javascript:;" class="link">超链接一</a></li>
    			<li><a href="javascript:;" class="link">超链接二</a></li>
    			<li><a href="javascript:;" class="link">超链接三</a></li>
    		</ul>
    		
    	</body>
    </html>
    
    

    2.2事件的绑定

    使用 对象.事件=函数 的形式绑定响应的函数

    他只能同时为一个元素的一个事件绑定一个响应的函数
    不能绑定多个,如果绑定多个,则后边会覆盖掉前边的

    addEventListener
    IE8不支持

    • 通过这个方法也可以为元素绑定响应函数
    • 参数:
      • 事件的字符串,不要on
      • 回调函数,当事件触发时该函数会被调用
      • 是否在捕获阶段触发事件,需要一个布尔值,一般都传false
    可以为按钮绑定n个事件而不会产生覆盖
    btn01.addEventListener("click",function(){
          alert(1),
    },false);
    btn01.addEventListener("click",function(){
          alert(2),
    },false);
    btn01.addEventListener("click",function(){
          alert(3),
    },false);
    

    attachEvent()
    IE8特殊的

    attachEvent()

    • 在IE8中可以使用attachEvent()来绑定事件
    • 参数:
      事件的字符串,要on
      回调函数
    btn01.attachEvent("onclick",function(){
          alert(1);
    });
    btn01.attachEvent("onclick",function(){
          alert(2);
    });
    
    • 不同的是他是后绑定先执行,执行顺序和addEventListener()相反

    addEventListener()中的this,是绑定事件的对象
    attachEvent()中的this,是window
    需要统一两个方法的this

    兼容处理
    函数优化

    • 参数:
      • obj 要绑定事件的对象
      • eventStr 事件的字符串(不要on)
      • callback 回调函数
    fucntion bind(obj,eventStr,callback){
          if(obj.addEventListener){
                //大部分浏览器兼容的方式
                obj.addEventListener(eventStr,callback,false);
          }else{
                //IE8及以下
                obj.attachEvent("on"+eventStr,function(){
                      //在匿名函数中调用回调函数
                      callback.call(obj);//这样attachEvent()也能返回绑定事件的对象
                })
          }
    }
    

    3.事件的传播

    • 关于时间的传播网景公司和微软公司有不同的理解
    • 微软公司认为事件应该是由内向外传播,也就是当前事件触发时,应该先触发当前元素上的事件,然后再想当前元素的祖先元素上传播,也就是说事件应该在冒泡阶段执行。
    • 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后再向内传播给后代元素
    • W3C综合了两个公司的方案,将事件的传播分成了三个阶段
      • 捕获阶段
        在捕获阶段时,从最外层的祖先元素,向目标元素进行事件的捕获,但是默认此时不会触发事件
      • 目标阶段
        事件捕获到目标元素,捕获结束开始在目标玉山路上触发事件
      • 冒泡阶段
        事件从目标元素向他的祖先运输传递,依次触发祖先元素上的事件

    如果希望在捕获阶段就触发事件,可以将addEventListener()的第三个参数设置为true
    一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false

    • IE8及以下的浏览器中没有捕获阶段

    4.事件练习

    4.1拖拽 P118-120

    • 拖拽的流程
    • 当鼠标在被拖拽元素上按下时,开始拖拽
    • 当鼠标移动时被拖拽元素跟随鼠标移动
    • 单鼠标松开时,被拖拽元素固定在当前位置
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    		<style type="text/css">
    			#box1 {
    				 100px;
    				height: 100px;
    				background-color: red;
    				position: absolute;
    			}
    
    			#box2 {
    				 100px;
    				height: 100px;
    				background-color: yellow;
    				position: absolute;
    
    				left: 200px;
    				top: 200px;
    			}
    		</style>
    
    		<script type="text/javascript">
    			window.onload = function() {
    				/*
    				 * 拖拽box1元素
    				 *  - 拖拽的流程
    				 * 		1.当鼠标在被拖拽元素上按下时,开始拖拽  onmousedown
    				 * 		2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
    				 * 		3.当鼠标松开时,被拖拽元素固定在当前位置	onmouseup
    				 */
    
    				//获取box1
    				var box1 = document.getElementById("box1");
    				var box2 = document.getElementById("box2");
    				var img1 = document.getElementById("img1");
    
    				//开启box1的拖拽
    				drag(box1);
    				//开启box2的
    				drag(box2);
    
    				drag(img1);
    
    
    
    
    			};
    
    			/*
    			 * 提取一个专门用来设置拖拽的函数
    			 * 参数:开启拖拽的元素
    			 */
    			function drag(obj) {
    				//当鼠标在被拖拽元素上按下时,开始拖拽  onmousedown
    				obj.onmousedown = function(event) {
    
    					//设置box1捕获所有鼠标按下的事件
    					/*
    					 * setCapture()
    					 * 	- 只有IE支持,但是在火狐中调用时不会报错,
    					 * 		而如果使用chrome调用,会报错
    					 */
    					/*if(box1.setCapture){
    						box1.setCapture();
    					}*/
    					obj.setCapture && obj.setCapture();
    
    
    					event = event || window.event;
    					//div的偏移量 鼠标.clentX - 元素.offsetLeft
    					//div的偏移量 鼠标.clentY - 元素.offsetTop
    					var ol = event.clientX - obj.offsetLeft;
    					var ot = event.clientY - obj.offsetTop;
    
    
    					//为document绑定一个onmousemove事件
    					document.onmousemove = function(event) {
    						event = event || window.event;
    						//当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
    						//获取鼠标的坐标
    						var left = event.clientX - ol;
    						var top = event.clientY - ot;
    
    						//修改box1的位置
    						obj.style.left = left + "px";
    						obj.style.top = top + "px";
    
    					};
    
    					//为document绑定一个鼠标松开事件
    					document.onmouseup = function() {
    						//当鼠标松开时,被拖拽元素固定在当前位置	onmouseup
    						//取消document的onmousemove事件
    						document.onmousemove = null;
    						//取消document的onmouseup事件
    						document.onmouseup = null;
    						//当鼠标松开时,取消对事件的捕获
    						obj.releaseCapture && obj.releaseCapture();
    					};
    
    					/*
    					 * 当我们拖拽一个网页中的内容时,浏览器会默认去搜索引擎中搜索内容,
    					 * 	此时会导致拖拽功能的异常,这个是浏览器提供的默认行为,
    					 * 	如果不希望发生这个行为,则可以通过return false来取消默认行为
    					 * 
    					 * 但是这招对IE8不起作用
    					 */
    					//return false;
    
    				};
    			}
    		</script>
    	</head>
    	<body>
    
    		我是一段文字
    
    		<div id="box1"></div>
    
    		<div id="box2"></div>
    
    		<img src="img/an.jpg" id="img1" style="position: absolute;" />
    	</body>
    </html>
    
    

    return false让浏览不能访问复制稳了拖拽信息
    box1.setCapture和releaseCapture作用为获取所有焦点,即当alt后移动对应的部分并不会移动整体,而是会只移动选中部分

    4.2滚轮事件

    当鼠标滚轮向下滚动时,box1变长
    当滚轮向上滚动时,box1变短

    • onmousewheel 鼠标滚轮事件,会在滚轮滚动时触发,但是火狐不支持该属性

    在火狐中需要使用DOMMouseScroll来绑定滚动事件
    注意该事件需要通过addEventListener()函数来绑定

    • 判断鼠标滚轮的滚动方向

    IE和谷歌:
    event.wheelDelta 可以获取鼠标滚轮滚动的方向
    向上120,向下-120
    wheelDelta这个值我们不看大小只看正负

    火狐:
    event.detail
    向上-3 , 向下3

    • 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,
      这是浏览器的默认行为,如果不希望发生,则可以取消默认行为
      需要在函数最后加上false

    使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false,而需要使用event.preventDefault();来取消默认行为

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    		<style type="text/css">
    			#box1 {
    				 100px;
    				height: 100px;
    				background-color: red;
    			}
    		</style>
    		<script type="text/javascript">
    			window.onload = function() {
    
    
    				//获取id为box1的div
    				var box1 = document.getElementById("box1");
    
    				//为box1绑定一个鼠标滚轮滚动的事件
    				/*
    				 * onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发,
    				 * 	但是火狐不支持该属性
    				 * 
    				 * 在火狐中需要使用 DOMMouseScroll 来绑定滚动事件
    				 * 	注意该事件需要通过addEventListener()函数来绑定
    				 */
    
    
    				box1.onmousewheel = function(event) {
    
    					event = event || window.event;
    
    
    					//event.wheelDelta 可以获取鼠标滚轮滚动的方向
    					//向上滚 120   向下滚 -120
    					//wheelDelta这个值我们不看大小,只看正负
    
    					//alert(event.wheelDelta);
    
    					//wheelDelta这个属性火狐中不支持
    					//在火狐中使用event.detail来获取滚动的方向
    					//向上滚 -3  向下滚 3
    					//alert(event.detail);
    
    
    					/*
    					 * 当鼠标滚轮向下滚动时,box1变长
    					 * 	当滚轮向上滚动时,box1变短
    					 */
    					//判断鼠标滚轮滚动的方向
    					if (event.wheelDelta > 0 || event.detail < 0) {
    						//向上滚,box1变短
    						box1.style.height = box1.clientHeight - 10 + "px";
    
    					} else {
    						//向下滚,box1变长
    						box1.style.height = box1.clientHeight + 10 + "px";
    					}
    
    					/*
    					 * 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false
    					 * 需要使用event来取消默认行为event.preventDefault();
    					 * 但是IE8不支持event.preventDefault();这个玩意,如果直接调用会报错
    					 */
    					event.preventDefault && event.preventDefault();
    
    
    					/*
    					 * 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,
    					 * 这是浏览器的默认行为,如果不希望发生,则可以取消默认行为
    					 */
    					return false;
    
    
    
    
    				};
    
    				//为火狐绑定滚轮事件
    				bind(box1, "DOMMouseScroll", box1.onmousewheel);
    
                                    //为chrome绑定滚轮事件
                                    bind(box1, "onmousewheel", box1.onmousewheel);
    
    			};
    
    
    			function bind(obj, eventStr, callback) {
    				if (obj.addEventListener) {
    					//大部分浏览器兼容的方式
    					obj.addEventListener(eventStr, callback, false);
    				} else {
    					/*
    					 * this是谁由调用方式决定
    					 * callback.call(obj)
    					 */
    					//IE8及以下
    					obj.attachEvent("on" + eventStr, function() {
    						//在匿名函数中调用回调函数
    						callback.call(obj);
    					});
    				}
    			}
    		</script>
    	</head>
    	<body style="height: 2000px;">
    	<div id="box1"></div>
          </body>
    </html>
    
    

    4.3键盘事件

    键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document

    • onkeydown
    • 按键按下
    • 对于onkeydown来说如果一直按着某个按键不松手,则事件会一直触发
    • 当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常快
    document.onkeydown = function(event){
          event = event|| window.event;
          /*
          * 可以通过keyCode来获取按键的编码
          * 通过它可以判断哪个按键被按下
          */
    
          //判断一个y是否被按下
          if(event.keyCode === 89){
                alert("y被按下了");
          }
    }
    
    • 监听按键
    • altKey、ctrlKey、shiftKey
      这三个用来判断alt、ctrl、shift是否被按下,如果按下则返回true
    • keyCode
      每个按键都对应有code
    判断y和ctrl是否被同时按下
    if(event.keyCode === 89 && event.ctrlKey){
          console.log("ctrl和y都被按下了");
    }
    

    //在文本框中输入内容,输入onkeyDown的默认行为
    //如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中

    • onkeyup
      按键被松开

    练习-- 键盘移动div

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    		<style type="text/css">
    			#box1{
    				 100px;
    				height: 100px;
    				background-color: red;
    				position: absolute;
    			}
    			
    			
    		</style>
    		
    		<script type="text/javascript">
    			
    			//使div可以根据不同的方向键向不同的方向移动
    			/*
    			 * 按左键,div向左移
    			 * 按右键,div向右移
    			 * 。。。
    			 */
    			window.onload = function(){
    				
    				//为document绑定一个按键按下的事件
    				document.onkeydown = function(event){
    					event = event || window.event;
    					
    					//定义一个变量,来表示移动的速度
    					var speed = 10;
    					
    					//当用户按了ctrl以后,速度加快
    					if(event.ctrlKey){
    						speed = 500;
    					}
    					
    					/*
    					 * 37 左
    					 * 38 上
    					 * 39 右
    					 * 40 下
    					 */
    					switch(event.keyCode){
    						case 37:
    							//alert("向左"); left值减小
    							box1.style.left = box1.offsetLeft - speed + "px";
    							break;
    						case 39:
    							//alert("向右");
    							box1.style.left = box1.offsetLeft + speed + "px";
    							break;
    						case 38:
    							//alert("向上");
    							box1.style.top = box1.offsetTop - speed + "px";
    							break;
    						case 40:
    							//alert("向下");
    							box1.style.top = box1.offsetTop + speed + "px";
    							break;
    					}
    					
    				};
    				
    			};
    			
    			
    		</script>
    	</head>
    	<body>
    		<div id="box1"></div>
    	</body>
    </html>
    

    这里第一次运行时会有轻微的卡顿,后面的知识可以解决这个问题

  • 相关阅读:
    Android Media Playback 中的MediaPlayer的用法及注意事项(二)
    Android Media Playback 中的MediaPlayer的用法及注意事项(一)
    34. Search for a Range
    33. Search in Rotated Sorted Array
    32. Longest Valid Parentheses
    31. Next Permutation下一个排列
    30. Substring with Concatenation of All Words找出串联所有词的子串
    29. Divide Two Integers
    28. Implement strStr()子串匹配
    27. Remove Element
  • 原文地址:https://www.cnblogs.com/psyduck/p/14274532.html
Copyright © 2011-2022 走看看