JavaScript基础-事件

 

任务:

  • 事件概念

  • 事件分类及常见事件

  • DOM0级事件处理程序

  • 事件流

  • 事件执行阶段

  • DOM2级事件处理程序(指定捕获或冒泡)

  • event

  • 事件委托/事件代理

 

 

事件概念

  • 事件是指将用户跟页面进行交互的动作或行为统称为事件。比如点击事件。

  • 当发生指定事件时,开发人员可以去执行程序。

  • 也可以理解为用户和计算机交互的方式方法。

  • 事件通常与函数结合使用,函数不会在事件发生前被执行 (如用户点击按钮)。

 

 

事件分类及常见事件

事件大致可以分为:鼠标事件 、键盘事件、窗口事件 、动画事件、表单事件 、拖动事件、触摸事件等等。

事件的三要素

  1. 事件源: 发生事件的对象(事件发生在谁身上,谁就是事件源)。

  2. 事件类型: 在事件源上发生了什么类型的事件(点击、移入、拖拽)。

  3. 事件处理函数: 事件发生时,需要执行的操作。

例如:

点击button按钮,弹出我❤️你。
事件源: button按钮。
事件类型:  点击事件。
事件处理函数:弹出信息。

 

鼠标事件

 

onclick

onclick: 点击事件。

语法:

// html中
<标签 onclick="做一些想做的事情">
​
// js中
节点对象.onclick=function(){ "做一些想做的事情" };
​
​
<div onclick='fn()'></div>
function fn(){
  console.log('111')
}

 

 

onmouseover

onmouseover:当鼠标进入指定标签时触发。

语法:

// html中
<标签 onmouseover="做一些想做的事情">
​
// js中
节点对象.onmouseover=function(){ "做一些想做的事情" };

 

onmouseout

onmouseout: 当鼠标离开标签时触发(移出)。

语法:

// html中
<标签 onmouseover="做一些想做的事情">
​
// js中
节点对象.onmouseover=function(){ "做一些想做的事情" };

 

onmousemove

onmousemove:鼠标在一个元素上移动持续触发。

语法:

// html中
<标签 onmousemove="做一些想做的事情">
​
// js中
节点对象.onmousemove=function(){ "做一些想做的事情" };

 

 

键盘事件

onkeydown

onkeydown: 当键盘按键按压时触发。

语法:

// html中
<标签 onkeydown="做一些想做的事情">
​
// js中
节点对象.onkeydown=function(){ "做一些想做的事情" };

例子1:

<input type="text" onkeydown="myFunction()">
function fn(){
    alert("你在输入栏内按下一个键");
}

例子2:

document.addEventListener("keydown",keydown);
//键盘监听,注意:在非ie浏览器和非ie内核的浏览器
//参数1:表示事件,keydown:键盘向下按;参数2:表示要触发的事件
function keydown(event){
    //表示键盘监听所触发的事件,同时传递参数event
    switch(event.keyCode){
        case 37:
            alert("左键");
            break;
        case 39:
            alert("右键");
            break;
    }
}

 

 

onkeyup

onkeyup: 当键盘按键松开后触发。

语法:

// html中
<标签 onkeyup="做一些想做的事情">

// js中
节点对象.onkeyup=function(){ "做一些想做的事情" };

例子:

<input type="text" onkeyup="myFunction()">
function fn(){
	alert("你在输入栏内松开了一个键");
}

 

onkeypress

onkeypress: 当键盘按键被按下并松开一个键时触发。

语法:

// html中
<标签 onkeypress="做一些想做的事情">

// js中
节点对象.onkeypress=function(){ "做一些想做的事情" };

例子:

<input type="text" onkeypress="myFunction()">
function fn(){
	alert("你在输入栏内按了一个键");
}

注意: 这三者之间的顺序:

  • onkeydown

  • onkeypress

  • onkeyup

 

表单事件

onchange

onchange:会在域的内容改变时发生。

注意:在元素的值改变了且失去焦点时触发(两次的值一样不会触发)

语法:

// html中
<标签 onchange="做一些想做的事情">

// js中
节点对象.onchange=function(){ "做一些想做的事情" };

例如:

<input type="text" onchange="myFunction()">
function fn(){
	alert("输入的内容改变了");
}

 

oninput

oninput在inputtextarea的值发生改变时触发,不需要等到元素失去焦点,是实时的。它是HTML5的事件,可用于检测文本类输入框的值。

注意:从JS中修改值不会触发事件。

<input oninput='iptOninput()'  />


 function iptOninput() {
       console.log('iptOninput');
  }

 

onfocus

onfocus: 元素获得焦点时触发(通常用于 input, select等)。

语法:

// html中
<标签 onfocus="做一些想做的事情">

// js中
节点对象.onfocus=function(){ "做一些想做的事情" };

例如:

<input type="text" onfocus="fn()">
//  注意: focus不能写成函数名
function fn(){
	alert("全场灯光聚焦在你身上了");
}

 

onblur

onblur: 对象失去焦点时触发。

语法:

// html中
<标签 onblur="做一些想做的事情">

// js中
节点对象.onblur=function(){ "做一些想做的事情" };

例如:

<input type="text" onblur="myFunction()">
// 注意: 函数名不能写成blur
function fn(){
	alert("失焦了");
}

 

 

框架/对象事件

onload

onload : 在页面或图像加载完成后触发。

语法:

// html中
<body onload="做一些想做的事情">  // 不用

// js中
window.onload=function(){ "做一些想做的事情" };

例子1:

<img src="xxxx.png" onload="onload()">
<script>
  function onload(){
    alert("图片加载完成");
  }
</script>

例子2:

<script>
  window.onload= function(){
  	alert('页面加载完成')
  }
</script>

 

onresize

onresize: 窗口或框架被重新调整大小时触发。

语法:

// html中
<body onresize="做一些想做的事情">  // 不用

// js中
window.onresize=function(){ "做一些想做的事情" };

例子:

<script>
  window.onresize= function(){
  	alert('页面大小改变了!')
  }
</script>

 

 

事件流

概念:事件流指的当某个事件触发时,该事件在嵌套标签之间的触发的顺序。

根据流向不同事件流分为2类

  • 冒泡:事件流顺序为先从具体的子标签开始触发,之后父标签触发事件,一直到顶层标签(html),之后JavaScript还会让document以及window对象进行触发。由子->父(祖先)

    span->p->div->body->html->document->window
    

     

  • 捕获:跟冒泡完全相反,先顶层父标签触发,在JavaScript中,先window对象触发,然后document-》html标签,一直到具体的子标签

    window->document->html->body->div->p->span
    

     

 

事件的传播

一个事件发生后,会在子元素和父元素之间传播。这种传播分成三个阶段。

流程:(三个阶段):

  1. 第一阶段(捕获阶段):从window对象触发,一直到具体的子标签为止,即从window对象传导到目标节点(上层传到底层)。

  2. 第二阶段(目标阶段):在目标节点上触发,也就是用户实际触发的标签执行一次事件。(可以理解为第一阶段的末尾,可以理解为第三阶段的开始。)

  3. 第三阶段(冒泡阶段):执行一次完整的冒泡,即从具体子标签开始触发,直到window对象为止,即从目标节点传导回window对象(从底层传回上层)。触发后。事件执行阶段就结束了。

 

DOM0级事件处理

事件处理程序;给某个标签指定某个事件,并指定要执行的代码。

注意: DOM0级事件处理程序只支持冒泡

  1. html标签中注册(不建议使用

    语法:

    <html标签 事件类型 = 事件处理函数></html标签>
    

    缺点: 全写在html中,代码冗余且没有分离,不方便后期维护。

  2. 节点注册

    语法:

    节点对象.事件类型 = 事件处理函数
    

    例如:

    box.onclick= function(){}
    

    缺点: 同一类型的事件不能注册多次。

 

         <div>
             这是div里的内容
             <p>这是p标签里的内容
                <span>这是span标签的内容</span>
             </p>
         </div>
 
 
 		let span = document.getElementsByTagName('span')[0];
        let p = document.getElementsByTagName('p')[0];
        let div = document.getElementsByTagName('div')[0];
        // dom0级事件处理程序
        div.onclick = function (){
            console.log('div被点击了');
        }
        p.onclick = function (){
            console.log('p被点击了');
        }
        span.onclick = function (){
            console.log('span被点击了');
        }
        //body
        document.body.onclick = function(){
            console.log('body被点击了');
        }
        //html
        document.documentElement.onclick = function(){
            console.log('html被点击了');
        }
        //document
        document.onclick = function(){
            console.log('document被点击了');
        }
        //window 
        window.onclick = function(){
            console.log('window被点击了');
        }

 

 

 

DOM2级事件处理

实现类似onclick的效果,即指定事件处理程序。只不过dom2级可以指定捕获阶段处理还是冒泡阶段处理,而dom0级只能在冒泡阶段处理。

创建

标签变量名.addEventListener("事件名",function(){},布尔型);
// 第一个参数:事件名     一定注意没有on!!!
// 第二个参数:指的事件触发要执行的函数
// 第三个参数(可选):是否在捕获阶段处理,true表示捕获阶段,false即冒泡阶段处理,不写则默认冒泡阶段处理。

 

 

	<div>
        这是div里的内容
        <p>这是p标签里的内容
            <span>这是span标签的内容</span>
        </p>
    </div>
    
    
       let span = document.getElementsByTagName('span')[0];
        let p = document.getElementsByTagName('p')[0];
        let div = document.getElementsByTagName('div')[0];
        
         //捕获
         span.addEventListener('click',spandemo,true);
         function spandemo(){
             console.log('span被点击了');
         }
         p.addEventListener('click',function(){
             console.log('p被点击了');
         },true);
         div.addEventListener('click',function(){
             console.log('div被点击了');
         },true);
         
         
         
    	//冒泡
        //  span.addEventListener('click',function(){
        //      console.log('span被点击了');
        //  },false);
        //  p.addEventListener('click',function(){
        //      console.log('p被点击了');
        //  },false);
        //  div.addEventListener('click',function(){
        //      console.log('div被点击了');
        //  },false);
        

 

注意: 如果第二个参数是一个函数名,那么需要注意:

		<p>段落文字ppppppppppppppppppp</p>

 		let p = document.querySelector('p')
        p.addEventListener('click', function (event) { // 匿名函数
            console.log(1);
        },false);

        p.addEventListener('click', function (event) {
            // 会触发
            console.log(2);
        },false);

        p.addEventListener('click', function (event) {
            // 会触发
            console.log(3);
        },false);

        p.addEventListener('click', function (event) {
            // 会触发
            console.log(4);
        },false);
        
        
        
        p.addEventListener('click', callback, false);
        // 不会触发
        p.addEventListener('click', callback, false);
        // 会触发
        p.addEventListener('click', callback1, false);
        
        function callback1(event) {
            console.log('callback1');
        }
        function callback(event) {
            console.log('callback');
        }

 

 

删除

标签变量名.removeEventListener("事件名",function(){},布尔型);
// 第一个参数:事件名
// 第二个参数:指的事件触发要执行的函数
// 第三个参数(可选):是否在捕获阶段处理,true表示捕获阶段,false即冒泡阶段处理,不写则默认冒泡阶段处理。

注意:

removeEventListener 会删除通过addEventListener创建的事件处理程序。但是有两个条件

  • 所有参数必须一致

  • 不能够删除第二个参数是匿名函数。

例如:

window.addEventListener(“click”,handler,false);
function handler(){
	console.log('冒泡:点击window了');
}
// 删除
 window.removeEventListener("click",handler,false);
		 <div>
            这是div里的内容
            <p>这是p标签里的内容
                <span>这是span标签的内容</span>
            </p>
        </div>
        
		
		let span = document.getElementsByTagName('span')[0];
        let p = document.getElementsByTagName('p')[0];
        let div = document.getElementsByTagName('div')[0];
         // dom 2级 
         //捕获
         span.addEventListener('click',spandemo,true);
         function spandemo(){
             console.log('span被点击了');
         }
         p.addEventListener('click',function(){
             console.log('p被点击了');
         },true);
         div.addEventListener('click',function(){
             console.log('div被点击了');
         },true);
         //删除捕获
         span.removeEventListener('click',spandemo,true);
         p.removeEventListener('click',function(){
             console.log('p被点击了');
         },true);
         div.removeEventListener('click',function(){
             console.log('div被点击了');
         },true);

 

 

事件处理小结

DOM0级(冒泡)

 // HTML标签中  不推荐
 <p on事件名="要执行的代码"></p>
// js中:
节点对象.on事件名 = function(){
}

 

DOM2级

节点对象.addEventListener()
节点对象.removeEventListener()

 

 

event

概念:当某个事件触发时,JavaScript会自动收集该事件的相关信息并包装成一个event原生对象,并自动作为实际参数传入事件处理程序中,我们可以在事件处理程序定义一个形式参数来接收并使用。

event对象常用的属性:

  • target:保存了触发该事件的具体标签

  • currentTarget:指的是当前事件执行阶段正在处理的标签,会随着事件执行阶段的进行而变化。

  • preventDefault():会取消原有标签的默认行为,比如提交按钮、超链接等

  • stopPropagation():取消进一步的冒泡。

  • type:该事件的类型,返回一个字符串。

  • clientX:当发生事件时,鼠标相当于窗口的x坐标,以窗口的左上角为原点。

  • clientY:当发生事件时,鼠标相当于窗口的Y坐标,以窗口的左上角为原点。

  • eventPhase: 是在事件传播的第几个阶段

注意: 同一个事件只会有一个event对象,event对象可以通过事件流传递给父标签的事件处理程序中。

	<div>
        <button>登录</button>
        <a href="http://www.baidu.com" onclick="demo2(event)">百度</a>
    </div>
    
    
    
     	let btn = document.getElementsByTagName('button')[0];
        btn.addEventListener("click",demo,false);
        let div = document.getElementsByTagName("div")[0];
        div.addEventListener("click",demo,false);
        document.body.addEventListener("click",demo,false);
        function demo(e){
            console.log('currentTarget:',e.currentTarget);
            console.log("target",e.target);
        }

        function demo2(e){
            //阻止默认
            e.preventDefault();
            //阻止冒泡
            e.stopPropagation();
            console.log('偏不让你访问百度');
        }
    

 

 

 

例子:

<div>
  <p>点击</p>
</div>
let div = document.querySelector('div');
let p = document.querySelector('p');

div.addEventListener('click', callback, true);
p.addEventListener('click', callback, true);
div.addEventListener('click', callback, false);
p.addEventListener('click', callback, false);

function callback(event) {
  let tag = event.currentTarget.tagName;
  console.log(event.type);
  console.log("Tag:'"+tag);
}
// 1
// Tag: 'DIV
// 2
// Tag: 'P
// 2
// Tag: 'P
// 因为addEventListener第三个参数不同,会导致绑定两个监听函数
// 3
// Tag: 'DIV

上面代码表示,click事件被触发了四次:<div>节点的捕获阶段和冒泡阶段各1次,<p>节点的目标阶段触发了2次。

  1. 捕获阶段:事件从<div><p>传播时,触发<div>click事件;

  2. 目标阶段:事件从<div>到达<p>时,触发<p>click事件;

  3. 冒泡阶段:事件从<p>传回<div>时,再次触发<div>click事件。

其中,<p>节点有两个监听函数(addEventListener方法第三个参数的不同,会导致绑定两个监听函数),因此它们都会因为click事件触发一次。所以,<p>会有两次输出。

 

 

事件委托

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(也叫事件委托)。

核心思想:

  • 给父标签或者祖先标签设置一个事件处理程序,然后利用event对象里的target来判断实际触发事件的标签,然后调用对应的处理代码

作用:减少事件处理程序的代码。

例子1:

<div>
    <p>
    <span></span>
    </p>
</div>
需求:都需要设置点击事件

分析: 因为div是span、p标签的父标签,给子标签设置点击事件,会因为冒泡机制,父标签也会触发,所以我们可以直接对div设置点击事件,利用event对象来判断实际用户点击的是哪个子标签,然后调用对应 的函数即可。

	<div id="box">
        这是div里的内容
        <p>这是p标签里的内容
            <span class="icon">这是span标签的内容</span>
        </p>
    </div>

  		let span = document.getElementsByTagName('span')[0];
        let p = document.getElementsByTagName('p')[0];
        let div = document.getElementsByTagName('div')[0];
        //事件委托进行优化
        document.body.addEventListener('click',handler);
        function handler(e){
            //业务逻辑
            if(e.target == span){
                 console.log('点击了span');
            }else if(e.target == p){
                console.log('点击了p标签');
            }else if(e.target ==div){
                 console.log('点击了div');
            }
        }
        document.body.removeEventListener('click',handler);

 

例子2:

	<ul>
        <li>1</li>
        <li>2</li>
    </ul>
    <p>p</p>
    <a>a</a>

document.onclick = function(e){
    // console.log(e.target);
    //对target判断\
    let type =e.target.nodeName;
    if(type=="A"){
    //超链接
    console.log("点击a了");
    }else if(type=="P"){
    console.log("点击p了");
    }else if(type=="LI"){
    console.log("点击Li了");
    }else if(type=="UL"){
    console.log("点击ul了");
    }else if(type=="HTML"){
    console.log("点击html了");
    }
}

 

事件委托应用场景:

let ul = document.querySelector('ul');

ul.addEventListener('click', function (event) {
  if (event.target.tagName === 'LI') {
    // xxxxxxx
  }
});

// 上面代码中,click事件的监听函数定义在<ul>节点,但是实际上,它处理的是子节点<li>的click事件。这样做的好处是,只要定义一个监听函数,就能处理多个子节点的事件,而不用在每个<li>节点上定义监听函数。而且以后再添加子节点,监听函数依然有效。

 

 

补充

自定义属性

有时,需要在HTML元素上附加数据(例如标识: 最常使用的是id),使得在js中使用,很好的一种解决方法就是自定义属性。

<div id="box" foo="bar">

let box = document.getElementById('box');
console.log(n.foo); // undefined
console.log(box.getAttribute('foo'));
box.setAttribute('foo', 'baz')

这种方法虽然可以达到目的,但是会使得 HTML 元素的属性不符合标准,导致网页代码通不过校验。

更好的解决方法是,使用HTML5提供的data-属性。

<div id="box" data-foo="bar">

然后,使用元素节点对象的dataset属性,它指向一个对象,可以用来操作 HTML 元素标签的data-xxx属性。

let box = document.getElementById('box');
box.dataset.foo // bar
box.dataset.foo = 'baz';
// 通过dataset对象 读写data-foo属性。

除了dataset属性,也可以用getAttribute('data-foo')setAttribute('data-foo')removeAttribute('data-foo')hasAttribute('data-foo')等方法操作data-xxx属性。

console.log(box.getAttribute('data-foo'));
box.setAttribute('data-foo','barbar')

 

 

扩展

自定义属性

data-后面的属性名有限制,只能包含字母、数字、连词线(-)、点(.)、冒号(:)和下划线(_)。而且,属性名不应该使用AZ的大写字母,比如不能有data-helloWorld这样的属性名,而要写成data-hello-world

转成dataset的键名时,连词线后面如果跟着一个小写字母,那么连词线会被移除,该小写字母转为大写字母,其他字符不变。反过来,dataset的键名转成属性名时,所有大写字母都会被转成连词线+该字母的小写形式,其他字符不变。比如,dataset.helloWorld会转成data-hello-world

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值