Event事件专题

84 篇文章 3 订阅

知识点 :

## 知识点

- 事件监听器
  - 事件监听和事件绑定的区别 
  - 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 事件监听和事件绑定的区别

  1. 事件绑定方式,写多个事件时,下面的事件会覆盖上面的事件;事件监听方式(不写on),多个事件都可同时存在;
  2. 事件绑定方式不可以取消事件;事件监听方式可以取消监听,但必须函数必须是匿名函数;

以下执行结果: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事件流

  1. - 事件冒泡 : 事件执行顺序从子级到父级。事件默认是冒泡执行
  2. - 事件捕获 :时间执行属性从父级到子级。addEventListener(type, listener[, options|useCapture])的第三个参数为true就是捕获执行,如果是false就是不捕获执行,默认为false。
  3. 注意:事件执行冒泡和捕获,是否执行子级或父级事件和具体事件触发位置及子父级范围有关

时间冒泡: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])的第三个参数还可以传递对象

  1. - capture 是否在捕获阶段执行,true表捕获执行,false为冒泡执行
  2. - once 是否只执行一次。true设置只执行一次,false不止执行一次。设置后即使为捕获或冒泡执行,也只会执行一次
  3. - 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事件委托(事件代理)

- 事件委托的优点

  1. 可减少需要添加事件绑定的元素
  2. 可给新增DOM元素添加事件(在不刷新页面的情况下)

- 事件委托的缺点

  1. 事件处理函数中需要判断事件源增加逻辑复杂度。
  2. 祖父级和事件源之间不能有阻止冒泡(一旦阻止冒泡了,事件委托就不能使用)

需求:在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 事件

  1. mouseover和mouseout事件,如果鼠标移入或移出子元素,也会触发mouseover和mouseout事件。
  2. 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 取消冒泡

  1. 子级元素本身有事件,并且不想执行父级元素的事件时,可以使用取消事件冒泡实现。
  2. Event.cancelBubble = true方法,在IE中也支持,之后才支持高级浏览器;
  3. 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 鼠标位置获取

  1. Event.clientX、Event.clientY:获取鼠标相对于元素的可视区域的位置,元素也可以是document或body
  2. 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.键盘事件

  1. - keydown、keyup
  2. - Event.keyCode、Event.key
  3. - Event.altKey、Event.ctrlKey、Event.shiftKey
  4. - 制作组合键

键盘事件和属性:

  • 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.鼠标滚动事件

  1. - mousewheel 和 DOMMouseScroll 事件。两个事件同时写不会有冲突
  2. - 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>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值