DOM高级

事件模型

  • 基本事件模型:也称为DOM0事件模型,是浏览器初期出现的一种比较简单的事件模型,主要通过HTML事件属性,为指定标签绑定事件处理函数。由于这种模型应用比较广泛,获得了所有浏览器的支持,目前依然比较流行。但是这种模型对于HTML文档标签依赖严重,不利于JavaScript独立开发
  • DOM事件模型:由W3C制订,是目前标准的事件处理模型。所有符合标准的浏览器都支持该模型,IE怪异模式不支持。DOM事件模型包括DOM2事件模块和DOM3事件模块,DOM3事件模块为DOM2事件模块的升级版,略有完善,主要是新增了一些事情类型,以适应移动设备的开发需要,但大部分规范和用法保持一致。
  • IE事件模型:IE4.0及其以上版本浏览器支持,与DOM事件模型相似,但用法不同
  • Netscape事件模型:由 Netscape4浏览器实现,在 Netscape6中停止支持

事件流

事件流就是多个节点对象对同一种事件进行响应的先后顺序,主要包括以下3种类型

  • 冒泡型 事件从最特定的目标向最不特定的目标( document对象)触发,也就是事件从下向上进行响应,这 个传递过程被形象地称为“冒泡”

  • 捕获型 事件从最不确定的目标(document对象)开始触发,然后到最特定的目标,也就是事件从上向下进行相应

  • 混合型 w3C的DOM事件模型支持捕获型和冒泡型两种事件流,其中捕获型事件流先发生,然后才发生冒泡型事件流。两种事件流会触及DOM中的所有层级对象,从 document对象开始,最后返回 document对象结束。因此,可以把事件传播的整个过程分为3个阶段

    • 捕获阶段:事件从 document对象沿着文档树向下传播到目标节点,如果目标节点的任何一个上级节点注册了相同的事件,那么事件在传播的过程中就会首先在最接近顶部的上级节点执行,依次向下传播
    • 目标阶段:注册在目标节点上的事件被执行
    • 冒泡阶段:事件从目标节点向上触发,如果上级节点注册了相同的事件,将会逐级响应,依次向上传播

绑定事件

  • 静态绑定:把JS脚本作为属性值,直接赋值给事件属性
  • 动态绑定:使用DOM对象的事件属性进行赋值
  • 事件处理函数:事件处理函数是一类特殊的函数,与函数直接量结构相同,主要任务是实现事件处理,为异步调用,由事件触发进行相应。

绑定事件的事件机制(DOM0事件)

使用on+事件名这种方式注册的事件叫做DOM0级事件 所有浏览器都支持这种事件绑定

var oOuter = my.getID("outer");
var oInner = my.getID("inner");
var oCon = my.getID("con");

//DOM 0级事件 在所有浏览器中都是冒泡的形式
oOuter.onclick = function () {
    alert("outer");
}
oInner.onclick = function () {
    alert("inner");
}
oCon.onclick = function () {
    alert("con");
}
var oBox = document.getElementById("box");
/*使用DOM0级事件 对同一个元素绑定同一个事件 只能执行一次
        后边的绑定会把前边的绑定给覆盖掉*/
/*oBox.onclick = function () {
            alert(1);
        }
        oBox.onclick = function () {
            alert(2);
        }
        oBox.onclick = function () {
            alert(3);
        }
        oBox.onclick = function () {
            alert(4);
        }*/


oBox.onclick = function () {
    alert(4);
}
// 取消DOM 0 级事件  直接给事件一个null即可
document.onclick = function () {
    oBox.onclick = null;
}

注册事件

  • 在DOM事件模型中,通过调用对象的addEventListnenr()方法注册事件
    • type:注册事件的类型名,事件类型与事件属性不同,事件类型名没有on前缀,例如,对于事件属性 onclick来说,所对应的事件类型为 click
    • listener:监听函数,即事件处理函数,在指定类型的事件发生时将调用该函数,在调用这个函数时,默认传递给它的唯一参数是 event对象
    • useCapture:是一个布尔值,如果为true,则指定的事件处理函数将在事件传播的捕获阶段触发,如果为 false,则事件处理函数将在冒泡阶段触发
  • 使用 addEventListener()方法能够为多个对象注册相同的事件处理函数,也可以为同一个对象注册多件处理函数。为同一个对象注册多个事件处理函数对于模块化开发非常有用。
  • IE事件模型使用attachEvent(etype,eventName)
    • type:事件类型:onclick、onkeyup等
    • eventName:设置事件处理函数
    • 使用attachEvent注册事件时,其事件处理函数的调用对象不再是当前事件对象的本身,而是window对象,如果想要获取当前对象,则使用event事件对象
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册事件(事件监听)</title>
</head>
<body>
    <div id="demo">demo</div>
    <div id="outer">
        <div id="inner">
            <div id="con">
                k看我的事件流
            </div>
        </div>
    </div>
<script>

    var oDemo = document.getElementById("demo");
    /*oDemo.addEventListener("click",function () {
        alert("demo1");
    },false);
    oDemo.addEventListener("click",function () {
        alert("demo2");
    },false);
    oDemo.addEventListener("click",function () {
        alert("demo3");
    },false);
    oDemo.addEventListener("click",function () {
        alert("demo4");
    },false);*/



    var oOuter = document.getElementById("outer");
    var oInner = document.getElementById("inner");
    var oCon = document.getElementById("con");
    /*oOuter.addEventListener("click",function () {
        alert("outer")
    },false)
    oInner.addEventListener("click",function () {
        alert("inner")
    },true)
    oCon.addEventListener("click",function () {
        alert("con")
    },true)*/


    // IE低版本事件监听
    /*oCon.attachEvent("onclick",function () {
        alert(1);
    })
    oInner.attachEvent("onclick",function () {
        alert(2);
    })*/



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

销毁事件

  • 在DOM事件模型中,使用removeEventListener()方法可以从指定对象中删除已经注册的事件处理函数
  • removeEventListener()只能处理addEventListener方法注册的事件
  • 当临时注册一个事件时,可以在处理完毕后删掉它,这样能够节省系统资源
  • IE事件模型使用detachEvent方法注销事件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="box">点击我有惊喜哦</div>
<button id="btn">取消惊喜</button>
<script>
    var oBox = document.getElementById("box");
    var oBtn = document.getElementById("btn");

    /*oBox.onclick = function () {
        alert("圣诞快乐");
    }
    //点击btn 取消box的DOM0点击事件
    oBtn.onclick = function () {
        oBox.onclick = null;
    }*/


    // 必须保证绑定的函数和移除的函数是同一个函数
    /*function f(){
        alert("圣诞快乐")
    }
    oBox.addEventListener("click",f,false);
    //点击btn 取消box的DOM2点击事件
    oBtn.onclick = function () {
        oBox.removeEventListener("click",f)
    }*/



    function f(){
        alert("圣诞快乐")
    }
    oBox.attachEvent("onclick",f);
    
    oBtn.onclick = function () {
        oBox.detachEvent("onclick",f)
    }
</script>
</body>
</html>

绑定事件兼容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>DOM2级事件的兼容</title>
</head>
<body>
<button id="btn">移除事件</button>
<div id="box">
box
</div>
<script src="./my.js"></script>
<script>
    var oBox = document.getElementById("box");
    var oBtn = document.getElementById("btn");
    function fn1() {
        alert("看我");
    }

    /*function addEvent(ele,type,fn,boo) {
        // DOM2级事件绑定兼容性封装
        if (ele.addEventListener){
            ele.addEventListener(type,fn,boo||false);
        }else if (ele.attachEventhEvent){
            ele.attachEvent("on"+type,fn)
        }else{
            ele["on"+type] = fn;
        }
    }*/
    my.addEvent(oBox,"click",fn1)

    /*function removeEvent(ele,type,fn){
        if (ele.removeEventListener){
            ele.removeEventListener(type,fn);
        }else if(ele.detachEvent){
            ele.detachEvent("on"+type,fn)
        }else{
            ele["on" + type] = null;
        }
    }*/

    oBtn.onclick = function () {
        my.removeEvent(oBox,"click",fn1)
    }
    /*// DOM2级事件绑定兼容性封装
    if (oBox.addEventListener){
        oBox.addEventListener("click",fn1,false);
    }else if (oBox.attachEvent){
        oBox.attachEvent("onclick",fn1)
    }else{
        oBox.onclick = fn1;
    }


    oBtn.onclick = function () {
        if (oBox.removeEventListener){
            oBox.removeEventListener("click",fn1);
        }else if(oBox.detachEvent){
            oBox.detachEvent("onclick",fn1)
        }else{
            oBox.onclick = null;
        }
    }*/

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

DOMContentLoaded事件

  • window.onload当所有的节点和资源加载完成才执行
  • 加载需要等待资源加载 并且还只能对window绑定一次
  • 解决方法1: 仍然是等资源加载完成才执行
  • 解决方法2 使用DOMContentLoaded事件 :当所有节点加载完毕就可以执行
  • DOMContentLoaded是DOM2级的事件 需要使用DOM2的监听方式来绑定事件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>DOMContentLoaded</title>
    <script>
        // window.onload当所有的节点和资源加载完成才执行
        // 加载需要等待资源加载 并且还只能对window绑定一次
        /*window.onload = function () {
            var oBox = document.getElementById("box");
            oBox.onclick = function () {
                alert(1);
            }
        }*/

        //解决方法1: 仍然是等资源加载完成才执行
        /*window.addEventListener("load",function () {
            var oBox = document.getElementById("box");
            oBox.onclick = function () {
                alert(1);
            }
        })*/


        //解决方法2  使用DOMContentLoaded事件  :当所有节点加载完毕就可以执行
        // onDOMContentLodeaded是DOM2级的事件  需要使用DOM2的监听方式来绑定事件
        window.addEventListener("DOMContentLoaded",function () {
            var oBox = document.getElementById("box");
            oBox.onclick = function () {
                alert(1);
            }
        },false)

    </script>
</head>
<body>
    <div id="box">1111</div>
</body>
</html>

event对象

  • event对象由事件自动创建,记录了当前事件的状态,如事件发生的源节点、键盘按键的响应状态、鼠标指针的移动位置、鼠标按键的响应状态等信息,
  • event对象的属性提供了有关事件的细节,其方法可以控制事件的传播
  • 2级DOM Events规范定义了一个标准的事件模型,它被除了IE低版本以外的所有现代浏览器所实现,而IE定义了专用的、不兼容的模型。简单比较两种事件模型如下:在DOM事件模型中, event对象被传递给事件处理函数,但是在IE事件模型中,它被存储在window对象的event属性中
    • bubbles:返回布尔值,指示事件是否是冒泡事件类型。如果事件是冒泡类型,则返回tue:否则返回 fasle
    • cancelable:返回布尔值,指示事件是否可以取消的默认动作,如果使用 preventDefault方法可以取消与事件关联的默认动作则返回值为mue:否则为false
    • target:返回事件的目标节点
    • type:事件类型
    • preventDefault():通知浏览器不要执行与事件关联的默认动作
    • stopPropagation():阻止事件在捕获、目标、冒泡阶段的进一步传播
    var oBox = document.getElementById("box");
    /*oBox.onclick = function () {
        console.log(window.event);
        // console.log(1);
    }
    oBox.onclick = function (e) {
        console.log(e);
        // console.log(1);
    }*/

    // 兼容性获取event事件对象:
    oBox.onclick = function (e) {
        var e = e || window.event;
        console.log(e);
    }

event事件的鼠标定位

  • clientX:以浏览器窗口左上顶角为原点,定位x轴坐标
  • offsetX:以当前事件的目标对象左上顶角为原点,定位x轴坐标
  • pageX:以 document对象(即文档窗口)左上顶角为原点,定位x轴坐标(不兼容IE)
  • screenX:计算机屏幕左上顶角为原点,定位x轴坐标
    var oCon = document.getElementById("con");
    oCon.onclick = function (e) {
        var e = e || window.event;
        // console.log(e.clientX,e.clientY);
        // console.log(e.offsetX,e.offsetY);
        // console.log(e.pageX,e.pageY);
        // console.log(e.screenX,e.screenY);

        console.log(getEventPage(e));
    }

    // pageX和pageY的封装
    function getEventPage(e) {
        if (e.pageX){
            return {
                x:e.pageX,
                y:e.pageY
            }
        }else{
            return {
                x:document.body.scrollLeft + e.clientX,
                y:document.body.scrollTop + e.clientY
            }
        }
    }

阻止传播

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>阻止传播</title>
    <style>
        #outer{
            width: 100px;
            height: 100px;
            background-color: red;
        }
        #inner{
            width: 100px;
            height: 50px;
            background-color: yellow;
        }
        #box{
            width: 100px;
            height: 20px;
            background-color: pink;
        }
    </style>
</head>
<body>
<div id="outer">
    <div id="inner">
        <div id="box">box</div>
        inner
    </div>
    outer
</div>
<script>
    var oOuter = document.getElementById("outer");
    var oInner = document.getElementById("inner");
    var oBox = document.getElementById("box");


    oOuter.addEventListener("click",function (ev) {
        // ev.stopPropagation?ev.stopPropagation():ev.cancelBubble = true;
        alert(1);
    },true);
    oInner.addEventListener("click",function () {
        alert(2);
    },true);
    oBox.addEventListener("click",function (ev) {
        // 阻止传播
        // 现代浏览器中:
       /* ev.stopPropagation();

        // ie678浏览器中
        ev.cancelBubble = true;*/

        // ev.stopPropagation?ev.stopPropagation():ev.cancelBubble = true;
        alert(3);
    },true);

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

阻止默认事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>阻止默认事件</title>
</head>
<body>
<a id="a1" href="http://www.baidu.com">百度一下你就知道</a>
<script>
    var oA1 = document.getElementById("a1");
    oA1.onclick = function (ev) {
        var ev = ev || window.event;

        // 阻止默认事件
        /*在现代浏览器:
        ev.preventDefault();
        在IE678:
        ev.returnValue = false;*/

        /*if(ev.preventDefault){
            ev.preventDefault();
        }else{
            ev.returnValue = false;
        }*/

        // ev.preventDefault?ev.preventDefault():ev.returnValue = false;

        return false;//如果说用来阻止默认事件,必须写在函数的最下边  因为他下边的代码不再执行
    }
</script>
</body>
</html>

键盘事件

键盘事件

  • 当用户操作键盘的时候会触发键盘事件
  • keydown:键盘被按下某个按键的时候触发,如果按住某一个按键,会不断触发该事件
  • keyup:释放某一个按键的时候触发。不是持续相应状态
    document.onkeydown = function (e) {
        var e = e || window.event;
        console.log(e);
    }

键盘事件属性

  • 键盘事件定义了很多属性

  • keyCode:对应键盘中对应键位的键值

  • shiftKey、ctrlKey、altKey是否按下shift strl alt按键 返回布尔值

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>键码</title>
    </head>
    <body>
    Jintiantianqizhenhao
    <script>
      document.onkeydown = function (ev) {
          /*var ev = ev || window.event;
          // console.log(ev)
          if (ev.keyCode == 67 && ev.ctrlKey) {
              alert("你又来复制了?");
          }
    
          return false;*/
          console.log(1);
      }
    </script>
    </body>
    </html>
    



### 键盘控制移动
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>键盘控制移动</title>
    <style>
        #box{
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            left: 0;
            top: 0;
        }
    </style>
</head>
<body>
<div id="box">

</div>
<script>
    var oBox = document.getElementById("box");
    /*document.onkeydown = function (ev) {
        // console.log(1);
        var ev = ev || window.event;
        if(ev.keyCode == 39){
            oBox.style.left = oBox.offsetLeft + 1 + 'px';
        }
        if(ev.keyCode == 38){
            oBox.style.top = oBox.offsetTop - 1 + 'px';
        }
        if(ev.keyCode == 37){
            oBox.style.left = oBox.offsetLeft - 1 + 'px';
        }
        if(ev.keyCode == 40){
            oBox.style.top = oBox.offsetTop + 1 + 'px';
        }
    }*/

    var shang = false,xia = false,zuo = false,you = false;
    var x = 0,y = 0;
    document.onkeydown = function (ev) {
        var ev = ev || window.event;
        /*if (ev.keyCode == 38){
            shang = true;
        }
        if (ev.keyCode == 39){
            you = true;
        }
        if (ev.keyCode == 40){
            xia = true;
        }
        if (ev.keyCode == 37){
            zuo = true;
        }*/

        switch (ev.keyCode){
            case 38:
                shang = true;
                break;
            case 39:
                you = true;
                break;
            case 40:
                xia = true;
                break;
            case 37:
                zuo = true;
                break;
        }
    }
    document.onkeyup = function (ev){
        var ev = ev || window.event;
        switch (ev.keyCode){
            case 38:
                shang = false;
                break;
            case 39:
                you = false;
                break;
            case 40:
                xia = false;
                break;
            case 37:
                zuo = false;
                break;
        }
    }
    timer = setInterval(function () {
        if (shang){
            y --;
        }
        if(xia){
            y ++;
        }
        if (zuo) {
            x --;
        }
        if(you){
            x ++;
        }

        oBox.style.top = y + "px";
        oBox.style.left = x + "px";
    },10)
</script>
</body>
</html>

敲回车提交表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>06.敲回车提交表单</title>
</head>
<body>
<form id="form" action="http://www.baidu.com">
    请输入手机号
    <input type="text" id="ipt">
</form>
<script>
    /*
        当用户输入完成敲击回车按键的时候。如果用户输入的都是11为纯数字  那么就让用户提交  否则不提交
     */
    var oForm = document.getElementById("form");
    var oIpt = document.getElementById("ipt");

    // 我们一般提交表单的时候,判断比较复杂 ,基本不会使用默认的跳转  而是我们主动跳转
    // 所以一般在提交事件中,首先阻止默认事件
    oIpt.onkeydown = function (ev) {
        var ev = ev || window.event;
        // ev.preventDefault?ev.preventDefault():ev.returnValue = false;

        if (ev.keyCode == 13){
            if (this.value.length == 11 && !isNaN(this.value)) {
                alert("输入正确");
                // 手动让表单提交  可以让form调用submit方法
                oForm.submit();
            }else{
                alert("重新输入");
                // ev.preventDefault?ev.preventDefault():ev.returnValue = false;
                return false;
            }
        }

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

事件委托

  • 事件委托(delegate) 也称为事件托管或者事件代理,就是把目标节点的事件绑定到祖先的节点上
  • 这种简单而优雅的事件注册方式是给予事件传播过程中,逐层冒泡总能被祖先元素捕捉到
  • 优点:优化代码提升性能,把html和js分离,防止动态添加或删除节点中注册事件的丢失现象
<!DOCTYPE html>
<html lang="en">
<head> 
    <meta charset="UTF-8">
    <title>事件委托</title>
</head>
<body>
<button id="btn">
    添加一个新元素
</button>
<ul id="box">
    <li>11</li>
    <li>22</li>
    <li>33</li>
    <li>44</li>
    <li>55</li>
</ul>
<script>
    var oBtn = document.getElementById("btn");
    var oBox = document.getElementById("box");
    var oLis = oBox.getElementsByTagName("li");

    /*事件委托的优点:
        1、可以对未来的元素绑定事件
        2、避免使用for循环 提高效率*/
    // 事件委托的原理:冒泡
    oBox.onclick = function (ev) {
        var ev = ev || window.event;
        // ev.target当前时间精确发生的元素
        console.log(ev.target);

        // 在这里this仍然是指向oBox
        // this.style.backgroundColor = "red";

        // 给精确的元素绑定点击事件,但是没有判断   所有元素都能触发
        // ev.target.style.backgroundColor = "red";

        if (ev.target.nodeName.toLowerCase() == "li" ){
            ev.target.style.backgroundColor = "red";
        }
    }

    oBtn.onclick = function () {
        var newLi = document.createElement("li");
        newLi.innerHTML = "newLi";
        oBox.appendChild(newLi);
    }
</script>
</body>
</html>

选择城市

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>选择城市</title>
    <link rel="stylesheet" href="./reset.css">
    <style>
        #outer{
            width: 400px;
            margin:20px auto;
        }
        #con{
            position: relative;
        }
        #select{
            height: 40px;
            background-color: grey;
            line-height: 40px;
        }
        #cityList{
            overflow: hidden;
            width: 400px;
            position: absolute;
            background-color: red;
            display: none;
        }
        #cityList li{
            width: 80px;
            text-align: center;
            margin: 10px;
            float: left;
        }
    </style>
</head>
<body>
<div id="outer">
    <h2 id="title">深圳</h2>
    <div id="con">
        <p id="select">点击我选择城市</p>
        <ul id="cityList">
            <li>深圳</li>
            <li>北京</li>
            <li>广州</li>
            <li>上海</li>
            <li>长沙</li>
            <li>南昌</li>
            <li>武汉</li>
            <li>焦作</li>
            <li>郑州</li>
            <li>太原</li>
            <li>草围</li>
        </ul>
    </div>
</div>
<script>
    var oCityList = document.getElementById("cityList");
    var oTitle = document.getElementById("title");
    document.onclick = function (ev) {
        var ev = ev || window.event;
        /*在现代浏览器中直接使用  ev.target
        在ie678中  使用 window.target.srcElement; */
        var target = ev.target || target.srcElement;
        if (target.id == "select"){
            oCityList.style.display = "block";
            return;
        }
        if(target.nodeName == "LI" && target.parentNode.id == "cityList"){
            oCityList.style.display = "none";
            oTitle.innerHTML = target.innerHTML;
            return;
        }
        oCityList.style.display = "none";
    }
</script>
</body>
</html>
posted @ 2023-01-12 22:36  z_bky  阅读(93)  评论(0)    收藏  举报