js事件(事件流、鼠标位置Client等、事件委托、事件冒泡等)

事件

事件:浏览器之中提前定义好的函数,在用户特定的操作下会被调用,这样的浏览器和用户的交互行为(给浏览器一个操作,浏览器给我一个反馈)

事件在程序之中是所有特效的起点,编写的功能就是通过事件去触发

事件的构成

1.事件源

2.事件类型

事件与函数的关系

函数是通过函数名来调用的

一般函数的调用要结合事件来调用

事件:用户与网页交互的重要方式

调用方式:

方式一:通过html标签调用

<标签 事件="函数名()">

方式二:js调用

对象.事件=函数名
注意:如果使用函数名,表示使用函数体;
     事件处理函数是由浏览器调用的,我们不要加括号,如果加了括号代表函数的返回值

例1:直接使用onclick在行内绑定函数

<input type="button" name="" onclick="fn()" value="点我" id="btn">

<script>
function fn(){
alert("何以解忧?唯有杜康")
}
</script>

例2:直接在id上绑定事件

<input type="button" name=""  value="点我" id="btn">

<script>
function fn(){
alert("何以解忧?唯有杜康")
}
var btn=document.getElementById('btn');
btn.onclick=fn;
</script>

事件对象

事件在触发的时候,浏览器会记录很对事件信息,这些事件信息会被存储在一个对象之中,完成后续的功能实现,这个存储数据的对象称为事件对象。

获取时间对象

所有的事件在触发的时候都会把事件对象放在事件处理函数之中进行使用

获取时间对象有兼容性问题。

事件对象兼容我们需要编写:

e=e|| event;

兼容原理:如果事件对象是以第一个参数传入事件处理函数之中的,那么此时e是一个对象,在||判断之中表示左侧为真(因为对象会被转换为布尔值true),如果e不是一个对象,那么左侧被判定为fasle,返回值为右侧内容返回内容为全局变量event。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
         #box{
            height: 200px;
            width: 200px;
            background-color: aquamarine;
            overflow: hidden;
        }
        
    </style>
</head>
<body>
    <div id="box"></div>
</body>
<script>
    var box=document.getElementById("box");
    function handlerClick(e){
       e=e||event;
       console.log(e)
    }
    box.onclick=handlerClick;
</script>
</html>

结果:
在这里插入图片描述

鼠标位置

因为鼠标位置是定位光标的坐标信息,所以浏览器给出了很多的参照物,不同的参照物得到的定位信息是不同的。

分类参照物
client参照物是浏览器可视区域边界
screen参照物是屏幕边界
offset距离鼠标最近元素的边界
page参照物是文档边界

获取光标定位的语法:参照物单词+x |y;

例如:以浏览器可视区域边界为参照物获取鼠标点击box时x和y轴距离,应该怎么编写属性?
e.clientX,e.clientY
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
         #box{
            height: 200px;
            width: 200px;
            background-color: aquamarine;
            overflow: hidden;
        }
        #pox{
            margin: 50px;
            width: 100px;
            height: 100px;
            background-color: bisque;
        }
        #jingubang{
            height: 1000px;
        }
    </style>
</head>
<body>
    <div id="jingubang"></div>
    <div id="box">
        <div id="pox"></div>
    </div>
</body>
<script>
    var box=document.getElementById("box");
    function handlerClick(e){
       e=e||event;
       var x = e.clientX; 
        var y = e.clientY;
        console.log( "client" ,  x , y );
        console.log( "screen" , e.screenX , e.screenY );
        console.log( "offset" , e.offsetX , e.offsetY );
        console.log( "page" , e.pageX , e.pageY );
    }
    box.onclick=handlerClick;
</script>
</html>

结果:
在这里插入图片描述

案例:会跳的图片

首先图片是位于屏幕下方正中间,这一步通过css就可以完成

获取dom对象,一个是图片的dom对象,另外一个就是屏幕对象(而这个就是document)

点击时,图片就会跳到需要跳到的那个地方, 首先需要获取点击哪个地方的偏移距离量,以可视区域为参照物。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
         #box{
            height: 100px;
            width: 100px;
            position: absolute;
            bottom: 0px;
            left: 45%;
            transition: left 1s , top 1s , transform 1s;
            transform: rotate(0deg);
        }
        #box img{
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
   <div id="box">
       <img src="./1.webp">
   </div>
</body>
<script>
    //首先图片是位于屏幕下方正中间,这一步通过css就可以完成
    //获取dom对象,一个是图片的dom对象,另外一个就是屏幕对象(而这个就是document)
    //点击时,图片就会跳到需要跳到的那个地方


    var box=document.getElementById("box");
    var rotate=0;
    function handlerClick(e){
        //首先需要获取点击哪个地方的偏移距离量,以可视区域为参照物。     
          e=e|| event;
          x=e.clientX;
          y=e.clientY;
          box.style.left=x+"px";
          box.style.top=y+"px";
          //每次转过去的时候,图片会自动旋转
          rotate += 360
            box.style.transform = "rotate(" + rotate + "deg)";
    }
    
    document.onclick=handlerClick;
</script>
</html>

结果:
在这里插入图片描述

键盘事件的事件对象

键盘事件的事件对象主要是获取键盘码

获取键盘事件对象,需要使用onkeydown获取,不能使用onkeyup获取

document.οnkeydοwn=函数名;

事件分类

鼠标事件

点击类:onclick(单击)/ondbclick(双击)

<body>
    <button id="btn">
        单击
    </button>
     <button id="btn1">
        双击
    </button>
    <script>
        function handlerClick(){
            alert("单击事件触发")
        }
        function handlerDbClick(){
            alert("双击事件触发")
        }
        
        btn.onclick=handlerClick;
        btn1.ondbclick=handlerDbClick;
    </script>
</body>

结果:
在这里插入图片描述

移动类事件

关键词事件
onmouseover鼠标覆盖
onmouseout鼠标出去
onmousemove鼠标移动

按键事件:mousedown(鼠标按下)、mouseup(鼠标提起)

事件流

事件流:事件的传播方式。

遇到嵌套元素点击内部元素的时候,我们是仅仅点击了内部元素还是同时点击了外部元素呢?

在浏览器看来两个元素都点击了。

问题是哪一个元素先获取到事件信息呢?

IE:事件信息传播是从内向外的,我们应该关注从内向外的事件传播顺序;

netscape:事件信息应该是较大层级向较小层级进行传播的,我们应该关注从外向内的事件传播;

ECMAScript规定事件传播阶段分成三个阶段:

1.由外向内的事件信息传播:事件捕获阶段

2.事件信息到达触发元素阶段:目标阶段

3.由内向外事件信息传播:事件冒泡

事件流:
在这里插入图片描述

目前浏览器关注的事件触发事件是目标阶段和事件冒泡阶段。注意:所有事件的传播都是从window开始或者终止的。

解析:

!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box{
            height: 200px;
            width: 200px;
            background-color: aquamarine;
            overflow: hidden;
        }
        #pox{
            margin: 50px;
            width: 100px;
            height: 100px;
            background-color: bisque;
        }

    </style>
</head>
<body>
    
    <div id="box">
        box
        <div id="pox">
            pox
        </div>
    </div>
    <script>
        

    </script>
</body>
</html>

结果:
在这里插入图片描述

事件冒泡

我们在给父子结构之中两个元素绑定了相同类型的事件时会发生事件冒泡触发,对于这种情况我们处理方式就叫事件冒泡。

阻止事件冒泡:

e.stopPropagation();

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box{
            height: 200px;
            width: 200px;
            background-color: aquamarine;
            overflow: hidden;
        }
        #pox{
            margin: 50px;
            width: 100px;
            height: 100px;
            background-color: bisque;
        }
    </style>
</head>
<body>

    <div id="box">
        <div id="pox"></div>
    </div>

    <script>
        // 我们在给父子结构之中两个元素绑定了相同类型的事件时会发生事件冒泡触发, 对于这种情况我们处理方式就叫做事件冒泡处理; 

        var box = document.getElementById("box");
        var pox = document.getElementById("pox");

        function handlerBoxClick(){
            alert("box事件触发");
        }
        // 我们如何阻止事件继续向上传递; 
        // - 事件对象阻止事件冒泡;
        function handelrPoxClick( e ){
            e = e || event;
            alert("pox事件触发");
            // 阻止事件冒泡的语法是 : 
            e.stopPropagation();
        }

        box.onclick = handlerBoxClick;
        pox.onclick = handelrPoxClick;


    </script>
</body>
</html>

结果:
在这里插入图片描述

事件抛发

主动触发我们定义好的事件

事件抛发的工具:dom.dispatchEvent(new Event(事件名));

适用场景:当我们进入页面的时候想要触发btn上面的事件,不需要用户点击。

解决方案:

  1. 调用所有btn的事件处理函数;

​ - 问题 : 不知道btn有多少事件处理函数。 有可能调用的时候话费较大的精力去查找这些事件处理函数;

​ handlerImportEvent1();

​ handlerImportEvent2();

​ 2. 使用事件抛发调用所有的事件处理函数;

​ 问题 : 抛发事件时,虚拟数据比较麻烦;

​ btn.dispatchEvent(new Event(“click”))

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">这是一个重要功能触发的按钮</button>
</body>
<script>
function handlerImportEvent1(){
   alert("重要事件1")
}
function handlerImportEvent2(){
   alert("重要事件2")
}
var btn=document.getElementById("btn");
btn.addEventListener("click",handlerImportEvent1);
btn.addEventListener("click",handlerImportEvent2);

btn.dispatchEvent(new Event("click"))

</script>
</html>

结果:
在这里插入图片描述

我们事件抛发可以自己创建事件自己调用

function init(){
     //初始化函数;
     //在初始化函数之中可以编写任何需要在页面初始化调用时的功能
     btn.dispatchEvent(new Event("click"));
}
// - 我们可以根据自己的需求定义特定事件; 
        // - 我们自定义事件绑定事件的目标元素可以是任意DOM对象,如果我们现在想要触发一个全局事件,我们可以把事件绑定给 document; 

        document.addEventListener( "init" , init );

我们可以在任意时机进行事件抛发,从而是现实功能的调用;函数的嵌套调用会导致程序的耦合发生

function timeoutCallback(){
            // 定时器的回调函数; 
            // - 这种方式会产生不必要的程序耦合; 
            // init();
            //事件抛发; 
            // - 没有任何耦合关系,吧耦合关系抛出给事件去进行处理; 
            document.dispatchEvent(new Event("init"))
        }

        setTimeout( timeoutCallback , 1000 )

事件委托

什么是事件委托?

就是本来给子元素添加事件,但是给在父元素天剑监听事件

我们在给一个项目添加事件的时候,发现有大量重复的元素需要添加相同的事件,这种情况可以使用事件委托来减少事件添加时冗余的事件添加代码。

事件委托可以解决异步创建元素的事件添加问题。

总结 : 我们把本该绑定在子集元素上的事件绑定给父级这种事件添加方式叫做事件委托

案例:页面之中存在30个li,给每个li元素都添加上一个事件。

我们通过事件冒泡的特性,可以考虑一个方法解决给每个li元素绑定一次事件的麻烦操作;我们把事件绑定给父级的ul元素,子集li触发事件时,父级的ul会接收到子集传递的事件, 从而让事件正常触发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        ul{
            background-color: aquamarine;
        }
        li{
            width: 50%;
            background-color: brown;
            color: #fff;
            margin-top: 10px;
        }
        .click{
            background-color: bisque;
        }
    </style>
</head>
<body>
    <ul>
        <div>增加的div</div>
        <div>增加的div</div>
        <div>增加的div</div>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li class="click">这是需要添加事件的元素</li>
        <li class="click">这是需要添加事件的元素</li>
        <li class="click">这是需要添加事件的元素</li>
        <li class="click">这是需要添加事件的元素</li>
        <li class="click">这是需要添加事件的元素</li>
        <li class="click">这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
        <li>这是需要添加事件的元素</li>
    </ul>
    <script> 

        var ul = document.querySelector("ul");
        // 这个事件处理函数是处理li被点击的事件处理函数; 
        function handlerClick(){
            alert("li 的事件触发了");
        }

        // ul.addEventListener("click" , handlerClick);

        // 我们使用上面这种方式直接添加事件的话,会导致事件在触发的时候太过随意,目标点不明确;
        // - 我们需要对上面的代码进行改进 : 我们在触发事件的时候需要对触发事件的元素进行判断,如果触发事件的元素不服符合要求,我们就不触发这个事件; 
        // - 我们需要针对 "事件源" 各项信息加以验证,确定是我们需要触发事件的元素我们再继续触发事件; 

        // 事件委托事件触发时,判断是否应该执行事件处理函数的函数; 
        function deleagation( e ){
            // - 我们要在这个判断函数之中找到事件源; 
            // - 事件源在事件处理函数之中 使用 e.target || e.srcElement 获取事件源。 
            e = e || event;
            // 获取事件源 :
            // origin : 源; 
            var origin = e.target || e.srcElement;
            // 判断是不是li ( DOM操作问题 )
            // 判定元素的标签类型 : dom.nodeName 
            // 使用nodeName 判定标签名的时候,返回的标签名字符串是大写的标签名;
            // console.log( origin.nodeName );
            if( origin.nodeName === "LI"){
                // 此时符合事件触发条件,我们就调用事件处理函数; 
                // - 此时为了让事件更加真实,我们需要给事件处理函数添加事件对象; 
                handlerClick( e );
            }
        }

        ul.addEventListener( "click" , deleagation);
       



    </script>
</body>
</html>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值