day15 - JavaScript伪数组、事件处理函数、事件对象、绑定事件的方式、移除事件、事件流(事件冒泡)、事件委托

一、伪数组

1.伪数组的含义:

拥有length属性,但是无法直接调用数组的方法或期望length属性有什么特殊的行为,但仍可以采用对真正数组遍历的方法来遍历它们。

伪数组转真数组:可以通过遍历数组,push到新的数组里面。

2.常见的伪数组:

html通用代码:

    <p>1</p>
    <p>2</p>
    <p>3</p>
  • 1.Arguments:
        function fn(){
            console.log(arguments) ;
        }
        fn()

输出:
在这里插入图片描述

  • 2.NodeList
        var oPs = document.querySelectorAll('p') ;
        console.log(oPs) ;

输出:
在这里插入图片描述

  • 3.HTMLCollection
        var oPs2 = document.getElementsByTagName('p') ;
        console.log(oPs2);

输出:在这里插入图片描述

二、事件

1.什么是事件:

事件是发生并得到处理的操作,即:事情来了,然后处理。HTML 事件是发生在 HTML 元素上的“事情”。当在 HTML 页面中使用 JavaScript 时,JavaScript 能够“应对”这些事件。

  • 常见的事件
    在这里插入图片描述
2.事件触发:

当用户点击按钮时,我们就说,触发了按钮的onclick事件

3.事件处理函数:

事件 :事件源.事件类型=事件处理函数

事件处理函数是异步的
事件处理函数是匿名函数是在事件发生以后,由系统调用
一般事件处理函数没有特定的返回值 , 但是也可以使用 return

        document.onclick = function () {
            console.log(666);
            return
            console.log(777);
        }
        //结果控制台打印:666  因为return会结束函数并返回值
  • 事件处理函数

事件处理函数的第一个参数表示的是事件对象
事件处理函数只有一个参数
事件对象是用户记录事情发生的整个过程

        document.onclick = function (a , b) {
            console.log(a) ;
            console.log(b) ;  //打印:undefined  说明事件处理函数只有一个参数
        }
  • 事件处理函数的参数 - 事件对象

1.大多数浏览器支持事件处理函数的第一个参数做事件对象
2.低版本浏览器只能使用event来记录事件对象,使用e会显示undefined
可以使用短路赋值,让浏览器兼容 e = e || event ;

  • target目标 — 具体是由哪个标签触发的
  • this 指向事件源
  • clientX,cilentY:相对于浏览器的可视窗口的x,y坐标

<body>
    <div class="a">
        <p>早上好!</p>
        <h3>小高今天早睡了吗</h3>
    </div>
    <div class="b">
        <h3>h3</h3>
        <span>span</span>
    </div>

    <script>
        document.onclick = function (e) {
            // 大多数浏览器支持事件处理函数的第一个参数做事件对象
            //低版本浏览器只能使用event来记录事件对象
            e = e || event ;

            // target目标  --- 具体是由哪个标签触发的
            console.log(e.target) ;
            
            // this 指向事件源
            console.log(e.this) ;   // #document

           // clientX,cilentY:相对于浏览器的可视窗口的x,y坐标
            console.log(e.clientX);
        }
        
    </script>
</body>

三、绑定事件的方式

1. 行内 js οnclick=“fn()” ,在HTML中添加 onclick。
行内 js 绑定事件会最先执行。

    <div class="a" onclick="fu()">小高今天早睡了吗</div>

2. 事件绑定 oDiv.onclick = function(){}
注意:此时的点击事件会覆盖前面的

<body>
    
    <div class="a" onclick="fn()">小高今天早睡了吗</div>

    <script>

        //拿对象
        var oDiv = document.querySelector('.a') ;

        oDiv.onclick = function () {
            console.log(1); 
        }

        oDiv .onclick = function () {
            console.log(2);
        }
        //点击 控制台会打印 2 ,因为后面的点击事件覆盖了前面的

    </script>
</body>

3. 事件监听 oDiv.addEventListener(类型,事件处理函数) — 不会覆盖前面的绑定事件

<body>
    
    <div class="a" onclick="fn()">小高今天早睡了吗</div>

    <script>

        //拿对象
        var oDiv = document.querySelector('.a') ;

        function fn(n) {
            console.log(666) ;
        }

        //不会覆盖
        oDiv.addEventListener('click' , function () {
            console.log(4);
        })
        
         //结果控制台打印 666 4
    </script>
</body>

JavaScript实现事件监听和兼容性

<body>
    
    <div class="a" onclick="fn()">小高今天早睡了吗</div>

    <script>
    
        //调用函数
        oDiv.addEventListener('click' , function () {
            console.log(4);
        })

        //功能:实现事件监听和兼容性
        function fn(ele , type , cb){
            // 先判断window对象下是否存在这个方法
            if(window.addEventListener){
                ele.addEventListener(type , cb)
            }else{
                ele.attachEvent('on' + type , cb)
            }
        }
    </script>
</body>

三、移除事件

- 行内 js 和普通事件绑定都可以通过重新赋值的方式,以覆盖的方式进行移除(onclick重新赋值时,任意值都可以。 一般建议写null)

<body>
    <div class="a" onclick="fn()">今天天气好好哦!</div>
    
    <script>
    
        var oDiv = document.querySelector('.a') ;

        oDiv.onclick = function () {
             console.log('是的!')
        }
        
        //移除事件,重新赋值
        oDiv.onclick = null ;

    </script>
</body>

- 事件监听的方式,需要写成具名函数才能被移除(注意:移除的时候,需要一个一个的移除) removeEventListener()

<body>
    <div class="a">今天天气好好哦!</div>
    
    <script>
    
        var oDiv = document.querySelector('.a') ;


        //添加事件监听
        addEvent(oDiv , 'click' , fn2)
        //移除事件监听
        removeEvent(oDiv , 'click' , fn2)

        function fn2() {
            console.log('真不错!')
        }

        //添加事件监听
        function addEvent(ele , type , cb){
            if(window.addEventListener){
                ele.addEventListener(type , cb)
            }else{
                ele.attachEvent('on' + type , cb)
            }
        }

        //移除事件监听
        function removeEvent(ele , type , cb){
        // 判断当前浏览器是否支持 removeEventListener 方法
            if(window.removeEventListener){
                ele.removeEventListener(type , cb)
            }else{
                ele.detachEvent('on' + type , cb)
            }
        }
    </script>
</body>

JavaScript实现事件监听移除和兼容性

        function removeEvent(ele , type , cb){
           // 判断当前浏览器是否支持 removeEventListener 方法
            if(window.removeEventListener){
                ele.removeEventListener(type , cb)
            }else{
                ele.detachEvent('on' + type , cb)
            }
        }

四、事件流

1.什么是事件流:

事件流描述的是从页面中接受事件的顺序

但有意思的是,微软(IE)和网景(Netscape)开发团队居然提出了两个截然相反的事件流概念,IE的事件流是事件冒泡流(event bubbling),而Netscape的事件流是事件捕获流(event capturing)。后来在W3C组织的统一之下,JS支持了冒泡流和捕获流,但是目前低版本的IE浏览器还是只能支持冒泡流(IE6,IE7,IE8均只支持冒泡流),所以为了能够兼容更多的浏览器,建议大家使用冒泡流。

  • 事件流包含的三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段
2.事件冒泡与事件捕获:

事件捕获:从里向外,事件捕获流的思想是不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件。

事件冒泡:从外向内,IE提出的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。

css通用样式:

        .a{
            width: 300px;
            height: 300px;
            background-color: pink ;
        }
        .a p {
            width: 200px;
            height: 200px;
            background-color: yellow ;
        }
        .a p span{
            width: 100px;
            height: 100px;
            display: block;
            background-color: green ;
        }

默认是事件冒泡
实现事件捕获的方式:addEventListener(type , fn , true) 第三个参数表示是否支持事件捕获

此时我们无论点击div , p 还是 span 三行文字都会打印。

<body>

    <div class="a">
        <p>
            <span></span>
        </p>
    </div>

    <script>
        var oDiv = document.querySelector('.a') ;
        var oP = document.querySelector('p') ;
        var oSpan = document.querySelector('span') ;

        // 默认是事件冒泡 --- 从里向外
        oDiv.addEventListener('click' , function() {
            console.log('我是最外面的') ;
        })
        oDiv.addEventListener('click' , function() {
            console.log('我是中间的') ;
        })
        oDiv.addEventListener('click' , function() {
            console.log('我是最里面的') ;
        })

    </script>
</body>

实现事件捕获:

        // 事件捕获 --- 从外向内
        oDiv.addEventListener('click', function () {
            console.log('我是最外面的');
        }, true)

        oP.addEventListener('click', function () {
            console.log('我是中间的');
        }, true)

        oSpan.addEventListener('click', function () {
            console.log('我是最里面的');
        }, true)
3.阻止事件冒泡:

w3c(主流浏览器)的方法是e.stopPropagation(),低版本IE则是使用e.cancelBubble = true

<!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>
        .a {
            width: 300px;
            height: 300px;
            background-color: pink;
        }

        .a p {
            width: 200px;
            height: 200px;
            background-color: yellow;
        }

        .a p span {
            width: 100px;
            height: 100px;
            display: block;
            background-color: green;
        }
    </style>
</head>

<body>

    <div class="a">
        <p>
            <span></span>
        </p>
    </div>
    
    <script>

        var oDiv = document.querySelector('.a')
        var oP = document.querySelector('p') ;
        var oSpan = document.querySelector('span')

        oDiv.onclick = function () {  
            console.log('div');
        }

        // 阻止事件冒泡
        oP.onclick = function (e) {
            e = e || event ;
             //判断浏览器是否支持e.stopPropagation
            if(e.stopPropagation){
               // 主流浏览器的写法
                e.stopPropagation()
            }else{
               // 低版本IE取消事件冒泡的方法
                e.cancelBubble = true ;
            }
            console.log('p') ;
        }

        oSpan.onclick = function (e) {
            if(e.stopPropagation){
                e.stopPropagation()
            }else{
                e.cancelBubble = true ;
            }
            console.log('span') ;
        }
    </script>
</body>
</html>

五、事件委托

当页面上的事件处理函数过多,会对性能造成影响,如果需要让每个li都有点击事件,,循环绑定事件 — 页面上实际会有很多的事件处理函数。循环绑定事件无法给将来的对象绑定事件这时候我们就需要用到事件委托

- 事件委托:事件冒泡
- 事件委托:子元素的事件都会触发父元素的事件
- 事件委托的实现:找到所有需要绑定事件的父元素,给父元素绑定事件,然后根据target来判断具体是由谁触发的
- 事件委托的优点:减少了事件处理函数,可以给未来的对象添加事件绑定

例题1:利用事件委托实现点击每个 li 打印的是当前点击的 li 的内容

<body>

    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
        <li>10</li>
    </ul>

    <div class="box">
        <div class="a">
            <p>
                <span id="s"></span>
            </p>
        </div>
    </div>

    <script>

        var oLis = document.querySelectorAll('li') ;
        var oUl = document.querySelector('ul') ;

        setTimeout(function () {
            var fragment = document.createDocumentFragment();
            for(var i = 11 ; i < 21 ; i++){
                var oLi = document.createElement('li') ;
                oLi.innerHTML = i ;
                fragment.appendChild(oLi) ;
            }
            oUl.appendChild(fragment)
        },1000)

        oUl.onclick = function (e) {
            console.log(e.target.innerHTML) ;
        }
    </script>
    
</body>

例题2:利用事件委托实现点击每个标签只出现点击标签的内容

<!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{
            width: 400px;
            height: 400px;
            border: 1px solid #000;
        }
        .a{
            width: 300px;
            height: 300px;
            background-color: yellow ;
        }
        .a p {
            width: 200px;
            height: 200px;
            background-color: pink
        }
        .a p span{
            width: 100px;
            height: 100px;
            display: block;
            background-color: green;
        }
    </style>
</head>
<body>

    <div class="box">
        <div class="a">
            <p>
                <span id="s"></span>
            </p>
        </div>
    </div>

    <script>

        var oDiv = document.querySelector('.a') ;
        var oP = document.querySelector('p') ;
        var oSpan = document.querySelector('span') ;
        var oBox = document.querySelector('.box') ;

        oBox.onclick = function (e) {
            e = e || event ;
            //判断当前点击元素的类名是否为a
            if(e.target.className === 'a'){
                console.log('点了黄色的div');
                return
            }
            //判断当前点击元素的标签名是否为P
            //HTML 返回 tagName 属性的值是大写的。
            if(e.target.tagName === 'P'){
                console.log('点了粉色的div');
                return
            }
            //判断当前点击元素的id是否为 s 
            if(e.target.id === 's'){
                console.log('点了绿色的div');
            }
        }
    </script>
    
</body>
</html>

className : 属性返回元素的类名 (返回的是字符串类型)
tagName:属性返回元素的标签名( HTML 返回 tagName 属性的值是大写的。)
target.id:属性返回元素的 id 名

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值