知识点 :
## 知识点
- 事件监听器
- 事件监听和事件绑定的区别
- addEventListener(type, listener[, options|useCapture])
- 事件流
- 事件冒泡
- 事件捕获
- 事件监听相关配置
- capture 是否在捕获阶段执行
- once 是否只执行一次
- passive 阻止取消默认事件
- removeEventListener 取消事件监听 (不能用匿名函数)
- Event 事件对象
- Event.target、Event.currentTarget 事件源
- 事件委托(事件代理)
- 事件委托的优点
1. 可减少需要添加事件绑定的元素
2. 可给新增DOM元素添加事件(在不刷新页面的情况下)
- 事件委托的缺点
1. 事件处理函数中需要判断事件源增加逻辑复杂度。
2. 祖父级和事件源之间不能有阻止冒泡
- mousenter、mouseleave 事件 - 这俩个事件 不会在鼠标移动父子级切换过程中触发
- Event.stopPropagation()、Event.cancelBubble 取消冒泡
- Event.clientX、Event.clientY、Event.pageX、Event.pageY 鼠标位置获取
- contextmenu 事件
- return false 和 Event.preventDefault() 阻止默认事件
- 键盘事件
- keydown、keyup
- Event.keyCode、Event.key
- Event.altKey、Event.ctrlKey、shiftKey
- 制作组合键
- 拖拽思路详解
- mousedown、mousemove、mouseup
- 拖拽公式:元素当前位置 = (鼠标当前位置 - 鼠标初始位置) + 元素初始位置
- 拖拽问题修复
- 限制范围拖拽
- 鼠标滚动事件
- mousewheel 和 DOMMouseScroll 事件
- Event.wheelDelta 和 Event.detail 滚轮方向获取
- 其他常用事件:
- dblclick
- blur、focus、change、input、submit、reset
- 表单其他方法:blur()、focus()、select()
1.事件监听器
1.1 事件监听和事件绑定的区别
- 事件绑定方式,写多个事件时,下面的事件会覆盖上面的事件;事件监听方式(不写on),多个事件都可同时存在;
- 事件绑定方式不可以取消事件;事件监听方式可以取消监听,但必须函数必须是匿名函数;
以下执行结果:onclick事件时只会打印2;使用事件监听addEventListener()时,会依次打印1,2
<style>
#box {
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
{
let box = document.querySelector("#box");
//事件绑定方式:通过事件绑定方式写多个事件,后面的事件会覆盖前面的事件
// box.onclick = () =>{
// console.log(1);
// }
// box.onclick = () =>{
// console.log(2);
// }
//事件监听方式:事件不能写on,多个事件都会执行
box.addEventListener('click',()=>{
console.log(1);
});
box.addEventListener('click',()=>{
console.log(2);
});
}
</script>
</body>
1.2 addEventListener(type, listener[, options|useCapture])
1.2.1事件流
- - 事件冒泡 : 事件执行顺序从子级到父级。事件默认是冒泡执行
- - 事件捕获 :时间执行属性从父级到子级。addEventListener(type, listener[, options|useCapture])的第三个参数为true就是捕获执行,如果是false就是不捕获执行,默认为false。
- 注意:事件执行冒泡和捕获,是否执行子级或父级事件和具体事件触发位置及子父级范围有关
时间冒泡:JS 中特性,事件会冒泡,执行子元素事件时,如果父元素有同样的事件,也会执行。
如下图:如果p,div,body,document都有点击事件,当p点击时,p,div,body,document事件都会执行,且按照p div body document的顺序执行
<style>
#box {
width: 400px;
height: 400px;
border: 1px solid black;
}
p {
display: block;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box">
<p></p>
</div>
<script>
{
let box = document.querySelector("#box");
let p = box.querySelector("p");
box.addEventListener('click',()=>{
console.log("div");//打印 div
});
//事件冒泡:在执行子元素的事件时,如果父元素也存在同样事件,父元素的事件也会执行
p.addEventListener('click',()=>{
console.log("p");//先打印 p 再打印div
});
}
</script>
</body>
事件捕获: 事件执行顺序从父级到子级
addEventListener(type, listener[, options|useCapture])的第三个参数为true就是捕获执行,如果是false就是不捕获执行,默认为false。
<style>
body {
border: 1px solid green;
}
#box {
width: 400px;
height: 400px;
border: 1px solid black;
}
p {
display: block;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box">
<p></p>
</div>
<script>
{
let box = document.querySelector("#box");
let p = box.querySelector("p");
let body = document.querySelector("body");
//事件捕获:通过addEventListener(type, listener[, options|useCapture])的第三个参数进行控制,如果是true就是捕获执行,是false就是不捕获执行,即事件默认为冒泡执行
body.addEventListener('click',()=>{
console.log("body");//只点击body时,只会打印body
},true);
box.addEventListener('click',()=>{
console.log("div");//在div范围内p标签范围外,点击会打印body div
},true);
p.addEventListener('click',()=>{
console.log("p");//会打印 body div p
},true);
}
</script>
</body>
注意:事件执行冒泡和捕获,是否执行子级或父级事件和具体事件触发位置及子父级范围有关:
如下图:
如果是事件冒泡,只点击body,会只打印body,点击了div会打印div body,点击了p 会打印 p, div, body;
如果是事件捕获,只点击了p,只会打印p, 点击了div,会打印div , p ,点击了body 会打印body,div,p
因为p div body 的范围不一致
1.2.2事件流的执行顺序
图片来源:http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
事件对象会随着DOM事件流从Window依次向下,最终传递给事件目标。但是在这个过程开始之前,事件对象的传递路径需要先被确定下来。
这个传递路径是一个有序的列表,里面包含了传递到事件目标需要经过的节点。而传递路径反映了文档的树结构。列表里面的最后一项就是事件目标,列表里面先于它的项指向目标的祖先节点,它的上一项指向目标的父节点。
比如上图由Window->Document->html->body->table->tr->td。一旦传递路径被确定了,事件对象就可以经历一个或者多个事件阶段。通常有三个阶段:捕获阶段,目标阶段,冒泡阶段。某些阶段可能会被跳过,如果浏览器不支持,或者事件对象的传播被停止了。例如,如果把cancelBubble
设置为true
,冒泡阶段将会被跳过,或者stopPropagation()
方法在传递之前就被调用的话,之后所有的阶段都会被跳过。
- 捕获阶段:事件对象从目标的祖先节点Window开始传播直至目标。
- 目标阶段:事件对象传递到事件目标。如果事件的type属性表明后面不会进行冒泡操作,那么事件到此就结束了。
- 冒泡阶段:事件对象以一个相反的方向进行传递,从目标开始,到Window对象结束。
链接:https://www.jianshu.com/p/dc1520327022
1.2.3事件监听第三个参数其他相关配置
addEventListener(type, listener[, options|useCapture])的第三个参数还可以传递对象
- - capture 是否在捕获阶段执行,true表捕获执行,false为冒泡执行
- - once 是否只执行一次。true设置只执行一次,false不止执行一次。设置后即使为捕获或冒泡执行,也只会执行一次
- - passive 阻止取消默认事件。true阻止取消默认事件,false不阻止取消默认事件
<style>
body {
border: 1px solid green;
}
#box {
width: 400px;
height: 400px;
border: 1px solid black;
}
p {
display: block;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box">
<p></p>
</div>
<script>
{
let box = document.querySelector("#box");
let p = box.querySelector("p");
let body = document.querySelector("body");
//addEventListener(type, listener[, options|useCapture])第三个参数传递对象时,有三个值
/*
- capture 是否在捕获阶段执行,true时为捕获执行
- once 是否只执行一次。
- passive 阻止取消默认事件
*/
body.addEventListener('click',()=>{
console.log("body");
},{
capture:true,
once:true
});
box.addEventListener('click',()=>{
console.log("div");
},{
capture:true
});
p.addEventListener('click',()=>{
console.log("p");
},{
capture:true//此处为捕获执行,但是body中设置了once:1,第一次点击p时会执行body div p;第二次以后就只会执行div p
});
}
</script>
</body>
passive阻止取消默认事件:
<body>
<a href="http://www.baidu.com">百度</a>
<script>
{
let a = document.querySelector("a");
a.addEventListener('click',(e)=>{
e.preventDefault();//a标签默认有点击后跳转功能, e.preventDefault()可以取消其默认跳转
},{
passive:true //当设置passive:true后,e.preventDefault()取消默认事件就会被阻止,默认事件又可以执行
});
}
</script>
</body>
1.3removeEventListener 取消事件监听 (不能用匿名函数)
如果需要取消事件监听,则添加事件监听时必须使用有名函数,才能保证取消的事件监听中的函数和添加的函数是同一个函数对象。
<style>
div {
width: 200px;
height: 200px;
background: red;
}
</style>
</head>
<body>
<div></div>
<button>取消事件</button>
<script>
{
let div = document.querySelector("div");
let btn = document.querySelector("button");
// div.addEventListener('click',()=>{
// console.log("div");
// });
// //发现这种方式取消不了div上的事件,因为div添加和取消监听里的函数虽然很像,但是不是同一个对象,所以取消不了
// btn.addEventListener('click',()=>{
// div.removeEventListener('click',()=>{
// console.log("div");
// });
// });
//正确取消监听事件,必须添加和取消监听时都使用有名函数
function fn(){
console.log("div");
}
div.addEventListener('click',fn);
//发现这种方式取消不了div上的事件,因为div添加和取消监听里的函数虽然很像,但是不是同一个对象,所以取消不了
btn.addEventListener('click',()=>{
div.removeEventListener('click',fn);
});
}
</script>
</body>
2.Event 事件对象
事件函数有一个默认的参数,即事件对象,存储的是和事件相关的属性。
2.1Event.target、Event.currentTarget 事件源
e.target : 事件触发的目标元素。即目标源。
e.currentTarget:事件绑定的元素。
<style>
div {
width: 200px;
height: 200px;
background: red;
}
p {
width: 100px;
height: 100px;
background: blue;
}
</style>
</head>
<body>
<div>
<p></p>
</div>
<script>
{
let div = document.querySelector("div");
let p = document.querySelector("p");
div.addEventListener('click',function(e){
// console.log(e);//获取到的是事件对象
console.log(e.target);//事件在哪个元素触发就是哪个
console.log(e.currentTarget);//永远是事件绑定的元素
});
}
</script>
</body>
2.2事件委托(事件代理)
- 事件委托的优点
- 可减少需要添加事件绑定的元素
- 可给新增DOM元素添加事件(在不刷新页面的情况下)
- 事件委托的缺点
- 事件处理函数中需要判断事件源增加逻辑复杂度。
- 祖父级和事件源之间不能有阻止冒泡(一旦阻止冒泡了,事件委托就不能使用)
需求:在ul点击时改变li的样式,但是不改变p标签的样式
<style>
li {
width: 100px;
height: 100px;
background: red;
margin: 10px;
}
p {
width: 50px;
height: 50px;
background: blue;
}
</style>
</head>
<body>
<ul>
<li>
<p></p>
</li>
<li>
<p></p>
</li>
<li>
<p></p>
</li>
<li>
<p></p>
</li>
</ul>
<script>
{
//需求:在ul点击时改变li的样式,但是不改变p标签的样式
let ul = document.querySelector("ul");
ul.addEventListener('click',function(e){
//通过事件委托,将li的事件点击委托给ul
//真正的事件委托,需要判断目标元素是不是要添加事件的元素
if(e.target.tagName == "LI"){
e.target.style.background = "yellow";
}
});
}
</script>
</body>
2.3mousenter、mouseleave 事件
- mouseover和mouseout事件,如果鼠标移入或移出子元素,也会触发mouseover和mouseout事件。
- mousenter、mouseleave 事件鼠标不会在父子级移动切换过程中触发。即不会受子级元素的干扰
<style>
div {
width: 100px;
height: 100px;
background: red;
}
p {
width: 50px;
height: 50px;
background: blue;
}
</style>
</head>
<body>
<div>
<p></p>
</div>
<script>
{
//需求:给div加上鼠标移入移出事件
let div = document.querySelector("div");
let p = document.querySelector("p");
div.addEventListener("mouseover",function(){
console.log("鼠标移入了");
});
div.addEventListener("mouseout",function(){
console.log("鼠标移出了");
});
}
</script>
</body>
结果:移动到子元素时会触发div移出事件,再触发div移入事件。即移入到div子级元素时,也会触发div的鼠标移入移出事件
使用mouseenter和mouseleave:
//需求:给div加上鼠标移入移出事件
let div = document.querySelector("div");
let p = document.querySelector("p");
//使用mouseenter和mouseleave事件:不受子级元素影响
div.addEventListener("mouseenter",function(){
console.log("鼠标移入了");
});
div.addEventListener("mouseleave",function(){
console.log("鼠标移出了");
});
2.4Event.stopPropagation()、Event.cancelBubble 取消冒泡
- 子级元素本身有事件,并且不想执行父级元素的事件时,可以使用取消事件冒泡实现。
- Event.cancelBubble = true方法,在IE中也支持,之后才支持高级浏览器;
- Event.stopPropagation()是w3c中标准的取消冒泡的方法;
<style>
div {
width: 100px;
height: 100px;
background: red;
}
p {
width: 50px;
height: 50px;
background: blue;
}
</style>
</head>
<body>
<div>
<p></p>
</div>
<script>
{
//需求:元素有自身的事件,不想执行父级的的事件
let div = document.querySelector("div");
let p = document.querySelector("p");
div.addEventListener('click',function(e){
console.log("div");
});
p.addEventListener('click',function(e){
//在子级中取消冒泡事件,就不会执行父级中的事件了
//最开始只有IE中能使用,现在高级浏览器版本也可以使用了
// e.cancelBubble = true;
//w3c中标准的取消冒泡事件方法
e.stopPropagation();
console.log("p");
});
}
</script>
</body>
2.5 Event.clientX、Event.clientY、Event.pageX、Event.pageY 鼠标位置获取
- Event.clientX、Event.clientY:获取鼠标相对于元素的可视区域的位置,元素也可以是document或body
- Event.pageX、Event.pageY:获取鼠标相对于页面左上角的位置。有滚动条时也相对于页面左上角
<style>
body {
width: 600px;
height: 600px;
border: 1px solid red;
}
div {
width: 100px;
height: 100px;
background: red;
}
p {
width: 50px;
height: 50px;
background: blue;
}
</style>
</head>
<body style="height:3000px">
<div>
<p></p>
</div>
<script>
{
//需求:获取鼠标位置
let div = document.querySelector("div");
let p = document.querySelector("p");
document.addEventListener('click',function(e){
//获取鼠标相对于可视区的坐标位置
console.log(e.clientX,e.clientY);//452 566
//获取鼠标相对于页面左上角的坐标位置
console.log(e.pageX,e.pageY);//452 1666
});
}
</script>
</body>
示例:鼠标跟随
最好使用pageX 和pageY ,这样在由滚动条时,就不会有问题
使用mousemove事件,在鼠标移动时,div跟随
<style>
div {
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div></div>
<script>
{
//需求:鼠标跟随
let div = document.querySelector("div");
document.addEventListener('mousemove',function(e){
//获取鼠标相对于页面左上角的坐标位置
div.style.top = e.pageY + 'px';
div.style.left = e.pageX + 'px';
});
}
</script>
</body>
3.contextmenu 鼠标右击事件
return false 和 Event.preventDefault() 阻止默认事件
注意:return false;只能onXXX绑定事件时使用;而e.preventDefault();可以使用绑定事件也可使用于事件监听,但不能使用与事件委托后的e.target的元素
鼠标右击事件一般都是加给document
示例:自定义右键菜单
<style>
body {
margin: 0;
padding: 0;
}
ul {
display: none;
position: absolute;
top: 0;
left: 0;
}
li {
width: 200px;
height: 30px;
border: 1px solid black;
list-style: none;
}
</style>
</head>
<body>
<ul>
<li>刷新</li>
<li>跳转</li>
<li>加载</li>
<li>首页</li>
</ul>
<script>
{
//需求:自定义鼠标右击菜单
let ul = document.querySelector("ul");
document.addEventListener('contextmenu',function(e){
//鼠标右击时首先取消默认鼠标右击事件
e.preventDefault();
//再让ul显示
ul.style.display = "block";
//鼠标右击时,让ul在右击的位置
ul.style.top = e.pageY + 'px';
ul.style.left = e.pageX + 'px';
console.log(e.pageX,e.pageY);
});
}
</script>
</body>
4.键盘事件
- - keydown、keyup
- - Event.keyCode、Event.key
- - Event.altKey、Event.ctrlKey、Event.shiftKey
- - 制作组合键
键盘事件和属性:
- keydown键盘按下事件;
- keyup键盘抬起事件;
- e.keyCode 键码;
- e.key 键值
- e.altKey:是否按下alt键
- e.ctrlKey是否按下ctrl键
- e.shiftKey是否按下shift键
//需求:键盘事件
document.addEventListener('keydown',function(e){
console.log("键盘按下");
console.log(e.keyCode);
console.log(e.key);
console.log(e.ctrlKey);
console.log(e.altKey);
console.log(e.shiftKey);
});
document.addEventListener("keyup",function(e){
console.log("键盘抬起");
});
组合键使用:
需求:ctrl+向上箭头 放大div;ctrl+向下箭头 缩小div;向上/下/左/右箭头,div向对应方向移动
<style>
div {
width: 200px;
height: 200px;
background: red;
position: absolute;
top: 50px;
left: 100px;
}
</style>
</head>
<body>
<div></div>
<script src="mTween.js"></script>
<script>
{
//需求:按上下左右箭头时,div向对应方向移动;按ctrl+向上箭头,div放大,按ctrl+向下箭头,div缩小
let div = document.querySelector("div");
var scale=1;
document.addEventListener('keydown',function(e){
let top = css(div,"top");
let left = css(div,"left");
console.log(top,left);
//上下左右的keyCode分别为:左 37;上38;右 39;下40; ctrl 17
let code = e.keyCode;
switch(code){
case 37:
css(div,"left",left-5);
break;
case 38:
css(div,"top",top-5);
break;
case 39:
css(div,"left",left+5);
break;
case 40:
css(div,"top",top+5);
break;
}
if(e.keyCode==38 && e.ctrlKey){
scale+=0.5;
div.style.transform='scale('+scale+')';
}
if(e.keyCode==40 && e.ctrlKey){
scale-=0.5;
div.style.transform='scale('+scale+')';
}
});
}
</script>
</body>
5.拖拽思路详解
- mousedown、mousemove、mouseup
- 拖拽公式:元素当前位置 = (鼠标当前位置 - 鼠标初始位置) + 元素初始位置
- 拖拽问题修复(会执行多次mouseup事件)
- 限制范围拖拽
思路:
1,获取元素div的初始位置(left,top)
2,获取鼠标初始位置
3,获取鼠标当前位置
4,元素当前位置 = (鼠标当前位置-鼠标初始位置)+元素初始位置
5,解决超出边界问题
需求:鼠标拖拽div到其他位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background: red;
position: absolute;
top: 50px;
left: 100px;
}
</style>
</head>
<body>
<div></div>
<script>
{
//需求:鼠标拖拽div到其他位置
/*
思路:
1,获取元素div的初始位置(left,top)
2,获取鼠标初始位置
3,获取鼠标当前位置
4,元素当前位置 = (鼠标当前位置-鼠标初始位置)+元素初始位置
5,解决超出边界问题
*/
let div = document.querySelector("div");
//获取元素div的初始位置
let divInitPos = {};
//获取鼠标初始位置
let initPos = {};
div.addEventListener('mousedown',function(e){
//获取元素初始位置必须在mousedown里,否则记录不到每次点击mousedown时元素的位置
divInitPos.t = div.offsetTop;
divInitPos.l = div.offsetLeft;
initPos.x = e.clientX;
initPos.y = e.clientY;
//监听鼠标移动,鼠标移动事件设置在document上,才不会甩出去
document.addEventListener('mousemove',drag);
//鼠标放下时,停止移动,即清除鼠标移动事件
//因为mouseup是在每次mousedown注册事件时就会进行注册,所以每点一次,以后就会进行累加,所以需要设置每次点击mousedown后,只执行一次mouseup
div.addEventListener('mouseup',function(e){
document.removeEventListener('mousemove',drag);
},{
once:true
});
});
function drag(e){
//获取移动时鼠标的当前位置
let curPos = {};
curPos.x = e.clientX;
curPos.y = e.clientY;
let divFinalPos = {};
divFinalPos.t = (curPos.y-initPos.y)+divInitPos.t;
divFinalPos.l = (curPos.x-initPos.x)+divInitPos.l;
//解决:拖拽时超出边界问题
//小于0时设置为0
divFinalPos.t = Math.max(0,divFinalPos.t);
divFinalPos.l = Math.max(0,divFinalPos.l);
//超过宽高后,等于宽高。获取浏览器可视宽高
let maxL = document.documentElement.clientWidth - div.offsetWidth;
let maxT = document.documentElement.clientHeight - div.offsetHeight;
divFinalPos.t = Math.min(maxT,divFinalPos.t);
divFinalPos.l = Math.min(maxL,divFinalPos.l);
//设置鼠标移动时,div位置跟着变化
div.style.top = divFinalPos.t + "px";
div.style.left = divFinalPos.l + "px";
}
}
</script>
</body>
</html>
6.鼠标滚动事件
- - mousewheel 和 DOMMouseScroll 事件。两个事件同时写不会有冲突
- - Event.wheelDelta 和 Event.detail 滚轮方向获取
mousewheel事件只兼容Chrome和IE;
- 滚轮向上滚动:打印120
- 滚轮停止向上滚动:打印240
- 滚轮向下滚动:打印-120
- 滚轮停止向上滚动:打印-240
DOMMouseScroll事件只兼容FireFox;
- 滚轮向上滚动:打印-3
- 滚轮停止向上滚动:打印-6
- 滚轮向下滚动:打印-3
- 滚轮停止向下滚动:打印6
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div></div>
<script>
{
let div = document.querySelector("div");
let width = div.offsetWidth;//width原始宽度
//mousewheel事件只能在Chrome和IE中使用
document.addEventListener('mousewheel',function(e){
//e.wheelDelta
width = e.wheelDelta>0? (width += 5):(width -= 5);
div.style.width = width + 'px';
});
//只能在FireFox中使用
document.addEventListener('DOMMouseScroll',function(e){
//e.detail
//e.detail<0时向上滚动
width = e.detail<0? (width += 5):(width -= 5);
div.style.width = width + 'px';
});
}
</script>
</body>
</html>
鼠标滚轮-方法封装:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div></div>
<script>
{
let div = document.querySelector("div");
let h = div.offsetHeight;//Height原始高度
toWheel(div,function(){
h+=5;
//这里可以使用this,是因为封装函数时,将其this指向进行了更改
this.style.height = h + 'px';
},function(){
h-=5;
this.style.height = h + 'px';
});
function toWheel(el,downFn,upFn){
el.addEventListener('mousewheel',function(e){
if(e.wheelDelta>0){
//向上
//如果直接调用this执行window,可以改变其this指向
upFn&&upFn.call(this);
}else{
//向下
downFn&&downFn.call(this);
}
});
el.addEventListener('DOMMouseScroll',function(e){
if(e.detail>0){
//向上
upFn&&upFn.call(this);
}else{
//向下
downFn&&downFn.call(this);
}
});
}
}
</script>
</body>
</html>
7.其他常用事件
- dblclick双击事件
- blur、focus、change、input、submit、reset事件
- blur鼠标光标失去焦点时执行;
- focus鼠标光标获取焦点时执行;
- change内容改变后执行。失去焦点时,如果内容发生改变就触发;比blur早执行
- input内容修改时执行。在内容发生变化时就触发,灵敏度高于change;
- 表单其他方法:blur()、focus()、select()
- select()选中文本框中的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button>双击</button>
<form action="">
<input type="text" id="txt">
<br>
<input type="submit" value="提交" id="sub">
<input type="reset" value="重置" id="res">
</form>
<script>
{
let btn = document.querySelector("button");
let txt = document.querySelector("#txt");
let sub = document.querySelector("#sub");
let res = document.querySelector("#res");
btn.addEventListener('dblclick',function(){
alert("双击了");
});
//blur、focus、change、input、submit、reset事件
txt.addEventListener('focus',function(){
console.log("获取焦点");
});
txt.addEventListener('blur',function(){
console.log("失去焦点");
});
txt.addEventListener('input',function(){
console.log("内容修改时");
});
txt.addEventListener('change',function(){
console.log("内容修改,且失去光标后");
});
//必须内容有改变才能提交
sub.addEventListener('submit',function(e){
e.preventDefault();
console.log("提交");
return false;
});
res.addEventListener('reset',function(){
console.log("重置");
});
//blur()、focus()、select()
//当按下空格键32时,获取光标;alt 18时失去光标;16 shift键选中文本
document.addEventListener('keydown',function(e){
console.log(e.keyCode);
let code = e.keyCode;
if(e.keyCode == 9){
txt.blur();
}
if(e.keyCode == 32){
txt.focus();
}
if(e.keyCode == 16){
txt.select();
}
});
}
</script>
</body>
</html>
8.select和selectstart的区别及阻止赋值
select:此事件在选择textarea或input内的内容后触发。因此只有input和textarea标签支持。Ctrl+A和鼠标选中都可以监听到。但是select事件不能阻止默认选中。
selectstart:鼠标左键开始选中时触发。用于禁止选择网页中的文字:另外ff/opera不支持此事件,ff可以用css控制:css: body { -moz-user-select: none; }。webkit浏览器可以使用“-khtml-user-select”,当然也可以使用onselectstart事件来阻止用户选定元素内文本。注意此事件不支持对input和textarea无效。对于textarea或input标签,可以监听到Ctrl+A的全选功能,但是鼠标左键全选无效。selectstart使用到非input和textarea标签上时,不会监听到Ctrl+A。会监听到鼠标左键开始选中时触发。
<input type="text" value="kaikeba">
<div>
kaikebakaikebakaikebakaikebakaikebakaikebakaikebakaikebakaikebakaikebakaikebakaikeba
</div>
let input = document.querySelector("input");
//对input和textarea使用:可以监听到Ctrl+A的全选功能,但是鼠标左键全选无效
input.addEventListener("selectstart",function(e){
console.log("input");
e.preventDefault();
});
如上结果:Ctrl+A全选时,才会被监听到,但是使用了e.preventDefault();所以不会被选中。使用鼠标左键选中时,不会被selectstart监听到,所以e.preventDefault()不起作用,还是可以进行选中。
let div = document.querySelector("div");
div.addEventListener("selectstart",function(e){
console.log("div");
e.preventDefault();
});
如上:selectstart使用到非input和textarea标签上时,不会监听到Ctrl+A。会监听到鼠标左键开始选中时触发。这里e.preventDefault()会阻止默认选中
input.addEventListener("select",function(e){
console.log("select");
e.preventDefault();
});
如上:使用select时,当鼠标选中后会触发,使用ctrl+a选中后也会触发。但是select事件不能阻止取消默认选中。所以使用e.preventDefault();也没有作用。
9.阻止赋值
要阻止文本被赋值,就要阻止ctrl+c , 右键赋值,和selectstart选中事件的默认行为。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.box{
width: 200px;
height: 200px;
background: red;
position: absolute;
top:200px;
left: 200px;
}
</style>
</head>
<body>
<div class="box">
这是一段文字
</div>
<script>
document.addEventListener('keydown',function(e){
if(e.keyCode == 67 && e.ctrlKey){
console.log('复制了')
// 阻止浏览器默认行为?
e.preventDefault();
}
})
// 选中文字事件
document.addEventListener('selectstart',function(e){
console.log('选中')
e.preventDefault()
})
// 阻止鼠标右键
document.addEventListener('contextmenu',function(e){
e.preventDefault();
})
</script>
</body>
</html>
10.自定义事件
需求:长按: 当鼠标在一个元素上长按超过 750 毫秒触发
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<a>长按</a>
<script>
// onclick ...
// 长按: 当鼠标在一个元素上长按超过 750 毫秒触发
let longTap = new Event("longTap",{
bubbles: true //如果设定为 false 也就是这个事件不冒泡,那就只能在那个元素上触发,那就只有这个一个元素是有这个事件的
});//自定义一个新事件
let timer = 0;
{
let a = document.querySelector("a");
a.addEventListener("mousedown",function(){
clearTimeout(timer);
timer = setTimeout(()=>{
a.dispatchEvent(longTap); // 在 a 标签触发,a 及它所有的父级都会有这个事件
// 如果是document触发,就只有 document 及 它的父级有这个事件,document 的内容就没有了
},750);
});
a.addEventListener("mouseup",function(){
clearTimeout(timer);
});
document.addEventListener("longTap",function(e){
if(e.target == a){
console.log("这是一个长按事件");
}
});
}
</script>
</body>
</html>