JavaScript-0819

本文详细介绍了JavaScript中获取元素尺寸、定位偏移量、滚动距离的方法,以及事件对象的使用,包括事件监听、事件流、事件冒泡、事件委托、阻止默认行为等核心概念。同时,通过实例展示了动态绑定事件、解绑事件、事件监听和解绑的兼容性处理,以及事件冒泡的控制。此外,文章还探讨了事件委托的优势,如支持未来元素和避免循环绑定事件,并给出了事件委托的实用案例。
摘要由CSDN通过智能技术生成
1、获取元素的尺寸
    1、window.getComputedStyle(dom对象)
    2、clientWidth/clinetHeight  内容+padding 没有px单位
    3、offsetWidth/offsetHeight  内容+padding+border
2、获取定位偏移量
    offsetLeft/offsetTop  每一个元素绝对有上级定位元素  如果没有最终以body计算
3、滚动距离
    scrollTop/scrollLeft  滚动距离
    scrollWidth/scrollHeight 滚动尺寸(完整的尺寸)
4、事件对象
    1、事件对象:
        事件触发时,系统会自动的调用函数 调用过程中传递了一个对象(事件对象)
    2、获取事件对象
        var event = e || window.event;
    3、按键码
        事件对象中有属性记录使用的按键(key,keyCode)
    


typora-root-url: img

鼠标坐标点

1、三组坐标点

<div class="div1"></div>
    <div class="div2"></div>
    <div class="div3"></div>
    <script>
        var divs = document.querySelectorAll('div');
        divs[0].onclick = function(e){
            var event = e || window.event;
            // offsetX,event.offsetY 以元素的左上角作为圆点计算坐标值
            console.log(event.offsetX,event.offsetY);
        }
        divs[1].onclick = function(e){
            var event = e|| window.event;
            // 以浏览器的左上角为坐标圆点计算
            console.log(event.clientX,event.clientY)
        }
        divs[2].onclick = function(event){
            // 以页面文档来计算的坐标圆点
            console.log(event.pageX,event.pageY)
        }
    </script>

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>
</head>
<body>
    <h1>X 轴坐标是 : <span class="x">950</span></h1>
    <h1>Y 轴坐标是 : <span class="y">64</span></h1>
    <script>
        document.onmousemove = function(event){
            document.querySelector('.x').innerHTML = event.pageX;
            document.querySelector('.y').innerHTML = event.pageY;
        }
    </script>
</body>
</html>

拖拽效果

<!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>
        div{ width: 100px; height: 100px; position: absolute; top:0;left:0;background-color: blue;}
    </style>
</head>
<body>
    <div></div>
    <script>
        /*
            拖拽效果就是需要控制元素的top与left值
            拖拽涉及到的事件:
                1、鼠标按下
                2、鼠标移动
                3、鼠标松手 元素就固定下
        */ 
        var divDom = document.querySelector('div');
        divDom.onmousedown  = function(){
            // 只有鼠标按下之后移动事件才会生效。所以移动事件必须要设置在按下事件中
            divDom.onmousemove = function(e){
                var event = e || window.event;
                var x= event.clientX - divDom.clientWidth/2;
                var y = event.clientY - divDom.clientHeight/2;
                divDom.style.top = y+'px';
                divDom.style.left = x+'px';
            }

        }
        // 鼠标松手之后  移动事件失效
        divDom.onmouseup = function(){
            // 解绑  一旦鼠标松手 将移动事件处理程序设置为null  就没有事件处理程序了 当鼠标移动时虽然可以触发 但是无效
            divDom.onmousemove = null;
        }
    </script>
</body>
</html>

事件流

事件流机制就是关于事件的传播方向。html结构是一层嵌套一层,可以看做为一组同心圆组成。每当在标签上触

发了一个事件,都可以理解同时触发了其他标签对应的事件。所以这种叫做事件传播。早期微软与网景公司在事件

处理,看法一致(都认为在标签上触发了事件,其实也可以理解为其他的标签也触发)。最后实现事件功能时完全相

微软:先在事件源上触发事件,然后在向上层元素触发同名事件(冒泡模型),直到window结束

网景:先在window上触发的事件,然后在逐层向下直到事件源上触发(捕获模型)

W3C进行整合时发现两家公司观点都正确。就直接将两种模型合并到一起

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-48dGUM0J-1660913546419)(/1660879190587.png)]

事件监听

1、动态绑定的缺点

<button>按钮</button>
<script>
    // 动态绑定事件,如果同一个元素 绑定多个同名事件 导致只有最后一次 生效
    document.querySelector('button').onclick = function(){
        console.log('张三写的代码逻辑');
    }

    document.querySelector('button').onclick = function(){
        console.log('你的逻辑代码');
    }

    window.onload = function(){
        console.log(1111)
    }

    window.onload = function(){
        console.log(222)
    }
    /*
        动态绑定为什么会出现覆盖问题
        因为每次都是使用dom.事件名称= 函数进行操作,这句话多次使用 就反复的在覆盖事件的属性值
        一旦事件触发 系统会自动的找到事件源dom对象调出对应的事件 然后将函数给运行
    */


</script>

2、事件监听语法

dom对象.addEventListener(事件名称,事件处理程序,模型类型)
事件名称 是没有on前缀的名称
事件处理程序,也是一个函数(如果需要使用事件对象 还是传递形参)
模型类型:要求是布尔值,false表示冒泡,true表示捕获 默认是冒泡模型 

3、使用示例

<button>按钮</button>
<script>
    // document.querySelector('button').addEventListener('click',function(){
    //     console.log('第一次绑定事件')
    // })
    // function fn(){
    //     console.log('第二次绑定')
    // }
    // document.querySelector('button').addEventListener('click',fn)
    // addEventListener 在IE下是存在兼容性问题
    document.querySelector('button').attachEvent('onclick',function(){
        console.log('ie')
    })
</script>

4、解决兼容性问题

/**
 * 绑定事件
 * @param {Document} elem 绑定事件的dom对象 
 * @param {String} eventName 事件名称 是没有on前缀的名称
 * @param {Function} handler 事件处理程序 
 */
function bindEvent(elem,eventName,handler){
    if(window.addEventListener){
        // 判断是w3c浏览器
       return elem.addEventListener(eventName,handler);
    }
    return elem.attachEvent('on'+eventName,handler);
}

事件解绑

行内方式解绑

<button onclick="console.log(123)">按钮</button>

<button class="delete">解除绑定</button>
<script>
    document.querySelector('.delete').addEventListener('click',function(){
        document.querySelector('button').removeAttribute('onclick')
    })
</script>

动态方式解绑

<button >按钮</button>

<button class="delete">解除绑定</button>
<script>
    document.querySelector('button').onclick = function(){
        console.log(123)
    }
    document.querySelector('.delete').addEventListener('click',function(){
        document.querySelector('button').onclick = null;
    })
</script>

事件监听解绑

1、事件解绑

<button>按钮</button>

    <button class="delete">解除绑定</button>
    <script>
        // [function(){},function(){}]
        document.querySelector('button').addEventListener('click', function () {
            console.log(123);
        })
        function fn(){
            console.log('第二个处理程序')
        }
        document.querySelector('button').addEventListener('click',fn);

        document.querySelector('.delete').addEventListener('click', function () {
            /*
                解除绑定的语法
                dom.removeEventListener(事件名称,事件处理程序)
                当需要进行解除绑定时 事件处理程序一定要使用有名称函数
            */
            document.querySelector('button').removeEventListener('click', function () {
                console.log(123);
            })
            document.querySelector('button').removeEventListener('click',fn)
        })

        console.log((function(){}) == (function(){}))//false

2、解决兼容性问题

<button>按钮</button>

<button class="delete">解除绑定</button>
<script src="common.js"></script>
<script>
    var btn = document.querySelector('button');
    var deleteDom = document.querySelector('.delete');
    function fn(){
        console.log(123)
    }
    // 为按钮绑定点击事件
    bindEvent(btn,'click',fn);

    deleteDom.onclick = function(){
        btn.detachEvent('onclick',fn)
    }
</script>

3、封装事件解绑函数

/**
 * 解除事件监听的绑定
 * @param {Document} elem 绑定事件的dom对象 
 * @param {String} eventName 事件名称 是没有on前缀的名称
 * @param {Function} handler 事件处理程序 
 */
function unbindEvent(elem,eventName,handler){
    try {
        elem.removeEventListener(eventName,handler);
    } catch (error) {
        elem.detachEvent('on'+eventName,handler);
    }
}

事件冒泡

<!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>
        .div1{ width: 400px; height: 400px; background-color: cadetblue;}
        .div2{ width: 300px; height: 300px; background-color:blue}
        .div3{ width: 200px; height: 200px; background-color: pink}
    </style>
</head>
<body>
    <div class="div1">
        <div class="div2">
            <div class="div3">

            </div>
        </div>
    </div>
    <script>
        document.querySelector('.div1').addEventListener('click',function(){
            console.log('div1被点击')
        })
        document.querySelector('.div2').addEventListener('click',function(event){
            console.log('div2被点击')
            event.stopPropagation();
        })
        document.querySelector('.div3').addEventListener('click',function(event){
            // 当div3被点击。触发了点击事件,继续向上传播点击事件,如果上层元素上也存在点击事件会按照顺序 执行,所以 事件冒泡存在缺点
            console.log('div3被点击');
            // 阻止事件冒泡
            // event.stopPropagation();
            // IE低版本阻止冒泡方式
            event.cancelBubble=true
        })

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

事件委托

未来元素需要处理事件 一定记得使用事件委托

1、未来元素绑定事件

<ul>
    <li>浮夸</li>
    <li>单车</li>
</ul>
<button>添加元素</button>
<script>
    document.querySelector('button').onclick = function(){
        var liDom = document.createElement('li')
        liDom.innerHTML = '你好机车哦!';
        document.querySelector('ul').appendChild(liDom);
    }

    document.querySelectorAll('li').forEach(function(dom){
        dom.addEventListener('click',function(){
            console.log(this.innerHTML)
        })
    })

</script>

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>
</head>
<body>
    <ul>
        <li>浮夸</li>
        <p class="mc">冒充者</p>
        <li>单车</li>
    </ul>
    <button>添加元素</button>
    <script>
        document.querySelector('button').onclick = function(){
            var liDom = document.createElement('li')
            liDom.innerHTML = '你好机车哦!';
            document.querySelector('ul').appendChild(liDom);
        }

        // document.querySelectorAll('li').forEach(function(dom){
        //     dom.addEventListener('click',function(){
        //         console.log(this.innerHTML)
        //     })
        // })
        // 事件委托 是借助于事件冒泡机制来实现的,子元素上触发事件后 父级元素也会触发同名事件
        document.querySelector('ul').addEventListener('click',function(event){
            // console.log('ul click');
            // 在事件冒泡的事件处理程序中this表示的是 父级元素 不是事件源
            // console.log(this);
            // 在事件冒泡中事件对象下的 srcElement、target 都可以表示事件源的dom对象
            // console.log(event)
            // 获取标签名称
            // console.log(event.target.nodeName,event.target.tagName);
            // 在使用事件委托机制时 只要能够确认绑定事件的元素 即可 不一定需要使用标签名称进行判断 可以使用其他的任何条件 只要能够区分标签即可
            if(event.target.nodeName == 'LI'){
                console.log(event.target.innerHTML);
            }else if (event.target.className == 'mc'){
                console.log('aaa')
            }
        })

    </script>

</body>
</html>

事件委托的好处:支持未来元素,避免循环绑定事件

事件委托的案例

<!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>
        table,
        table tr th,
        table tr td {
            border: 1px solid #0094ff;
        }

        .layer {
            width: 200px;
            height: 150px;
            position: absolute;
            top: 200px;
            left: 200px;
            background-color: #ccc;
            display: none;
            line-height: 38px;
        }
    </style>
</head>

<body>
    <div class="layer">
        <input type="text" class="username" /> <br />
        <input type="radio" class="changeSex" name="changeSex" value="" /><input type="radio" class="changeSex" name="changeSex" value="" /><br />
        <input type="text" class="age" /><br />
        <button id="set">修改</button>
    </div>



    <div>
        <input type="text" id="username" />
        <input type="radio" id="sexOne" name="sex" value="" /><input type="radio" id="sexTwo" checked name="sex" value="" /><input type="text" id="age" />
        <button id="add">添加</button>
    </div>
    <br />
    <table cellspacing="0" border="1" width="600px">
        <tr>
            <td>姓名</td>
            <td>性别</td>
            <td>年龄</td>
            <td>操作</td>
        </tr>
    </table>
    <script>
        var eidtParentDom = null;
        //页面上输入用户的姓名、性别、年龄 确认后 列表的方式显示添加的数据
        document.querySelector('#add').onclick = function () {
            // 获取到页面上输入内容
            var username = document.querySelector('#username').value;
            // 获取性别  input[name="sex"]:checked 从所有input中先筛选name值为sex 并且有checked属性的input
            var sex = document.querySelector('input[name="sex"]:checked').value;
            var age = document.querySelector('#age').value;
            // 创建tr节点
            var trDom = document.createElement('tr');
            trDom.innerHTML = `
                <td>${username}</td>
                <td>${sex}</td>
                <td>${age}</td>
                <td><button class="delete">删除</button></td>
                `
            document.querySelector('tbody').appendChild(trDom)
        }

        document.querySelector('table').addEventListener('click',function(event){
            if(event.target.className == 'delete' ){
                // 点击的是删除按钮
                document.querySelector('tbody').removeChild(event.target.parentElement.parentElement)
            }

        })

    </script>
</body>

</html>

阻止默认行为

页面中a标签与form标签具备默认行为,天生需要跳转地址

1、a标签

<!-- 1、直接在href上设置 javascript:; 表示执行空的js代码-->
<a href="javascript:;">百度</a>
<a href="" class="baidu">百度一下</a>
<script>
    // 2、在动态绑定中可以return false 阻止  千万别报错
    // document.querySelector('.baidu').onclick = function(){
    //     console.log(123)
    //     return false;
    // }

    // 3、使用事件对象
    document.querySelector('.baidu').addEventListener('click',function(event){
        // 阻止默认行为
        event.preventDefault();
    })
</script>

2、form标签

<form>
        <input type="text" >
        <input type="submit" class="sub"  value="ok">
    </form>
    <script>
        document.querySelector('.sub').addEventListener('click',function(event){
            console.log('你的代码有bug');
            event.preventDefault();
            // e.returnValue = false; 
        })
    </script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

goto_w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值