• 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>
    

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

  • 相关阅读:
    浏览器缓存机制
    关于CSRF的攻击
    关于CGI、FastCGI和PHP-FPM的关系
    PHP-FPM进程数的设定
    一个论坛引发的血案
    Django中的权限系统
    Django中使用ModelForm实现Admin功能
    Django中使用Bootstrap
    Django的用户认证
    vtkMapper
  • 原文地址:https://www.cnblogs.com/psyduck/p/14274532.html
Copyright © 2020-2023  润新知