1.事件

网页中的每个元素都可以产生某些事件。 比如:当用户单击按钮时,就发生一个鼠标单击(onclick)事件。 当用户点击提交按钮时,就发生一个提交数据(onsubmit)事件。 事件是可以被侦测到的行为。 每个元素都可以产生某些可以触发JavaScript函数的事件。
javaScript中的常用事件:
05.DOM编程 - 图1

1.1.javaScript中绑定事件方式

在javaScript中,给DOM元素绑定事件有三种方式:侵入式、绑定式、监听函数式。

  1. 侵入式事件方式:将javaScript事件直接写在html标签中

    1. <div onclick="add()">点我</div>
    2. <script>
    3. //事件处理函数
    4. function add(){
    5. console.log('点击了div对象');
    6. }
    7. </script>

    注意:此种方式的缺点是:javaScript事件与HTML代码混杂在一起。

  2. 绑定式事件方式:通过DOM对象,使用javaScript代码绑定一个事件

    <div>点我</div>
    <script>
     let divObj = document.getElementsByTagName('div')[0];
     //function()匿名函数就是事件处理函数
     divObj.onclick = function(){
         console.log('点击了div对象');
     }
    </script>
    

    注意:此种方式的优点是:

    1. 行间和事件分离。
    2. 可以给元素动态添加事件。
  3. 监听函数式事件方式:

    <div>点我</div>
    <script>
     let divObj = document.getElementsByTagName('div')[0];
     divObj.addEventListener('click',function(){
         console.log('点击了div对象');
     },false);
    </script>
    

    注意:addEventListener函数的三个参数:

    1. 事件名(没有前缀on)。
    2. 事件处理函数。
    3. 布尔类型(一般为false)。true:进行事件捕获; false:不进行事件捕获;

1.2.事件对象-event

event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
05.DOM编程 - 图2

1.2.1.鼠标坐标的使用

<head>
    <meta charset="utf-8">
    <title></title>
    <style>
        div{
            width: 200px;
            height: 200px;
            background-color: blue;
            margin: 100px;
        }
    </style>    
</head>
<body>
    <div><div>    
    <script>
        document.getElementsByTagName('div')[0].onmousemove = function(event){
            console.log('相对视口坐标:'+event.clientX+','+event.clientY);
            console.log('相对触发事件对象坐标:'+event.offsetX+','+event.offsetY);
        }
    </script>
</body>

1.2.2.keyCode的使用

//获取键盘按键的keyCode
document.onkeydown = function(event){
    console.log(event.keyCode);
}

常用按键的keyCode值:回车13, 空格32,上38,下40,左37,右39

1.3.事件冒泡与事件捕获

在页面上的一块可视区域中,其中可能会包括父元素可视区域与子元素可视区域。
此时,如果用户触发了子元素的某个事件,而父元素也具有相同的事件,那么事实上,我们并不能确定:用户到底是想触发子元素事件,还是想触发父元素事件。
解决这个问题的思路是:设计两种事件流:

  1. 当用户触发了子元素事件时,先触发子元素事件,再触发父元素事件。这就是事件冒泡。(默认)
  2. 当用户触发了子元素事件时,先触发父元素事件,再触发子元素事件。这就是事件捕获。

下面演示事件冒泡:

<head>
    <style>
        div{
            width: 200px;
            height: 200px;
            background-color: red;
        }
        div p{
            width: 100px;
            height: 100px;
            background-color: blue;
        }
    </style>
</head>
<body>
    <div>
        <p></p>
    </div>
    <script>
        let divObj = document.getElementsByTagName('div')[0];
        let pObj = divObj.getElementsByTagName('p')[0];
        divObj.onclick = function(){
            alert('父元素的点击事件被触发');
        }
        pObj.onclick = function(){
            alert('子元素的点击事件被触发');
        }
    </script>
</body>

阻止事件冒泡: event.cancelBubble = true;

pObj.onclick = function(event){
    alert('子元素的点击事件被触发');
    event.cancelBubble = true;
}

1.4.浏览器默认行为

默认行为:在某些事件中,浏览器内置了一些默认的功能。 如:单击鼠标右键会弹出菜单、提交按钮默认提交动作、按下字母键会输入一个字母等。 如果这些默认行为不能满足我们需要的功能,那么可以阻止默认行为,重写我们希望的行为。 阻止默认行为很简单,在事件处理函数中调用preventDefault方法即可。 阻止默认行为: event.preventDefault();
下面是一个自定义右键菜单案例:

<ul>
    <li>右键菜单项1</li>
    <li>右键菜单项2</li>
    <li>右键菜单项3</li>
</ul>
<script>
    let ulObj = document.getElementsByTagName('ul')[0];
    ulObj.style.border = 'solid 1px #666';
    ulObj.style.width = '100px';
    ulObj.style.position = 'absolute';
    ulObj.style.display = 'none';
    document.oncontextmenu = function(event){
        ulObj.style.display = 'block';
        ulObj.style.left = event.clientX+'px';
        ulObj.style.top = event.clientY+'px';
        event.preventDefault();
    }
    ulObj.onclick = function(){
        this.style.display = 'none';
    }
</script>

1.5.表单元素事件

1.5.1.表单元素常用事件

05.DOM编程 - 图3

1.5.2.表单验证

表单是Web应用中的一个重要组成部分,通过表单,可以让用户与服务器端进行交互。
通常的做法是:用户通过页面表单中的各种控件(文本框、单选按钮、下拉列表等等),填入数据,表单再将这些数据发送给服务器端,进行业务处理。
但是,用户在填入数据的过程中,很有可能会填入错误的数据。此时,就需要在页面上,对用户输入的数据进行合法性验证,以保证用户必须填入正确的数据,进而保证发送给服务器端的数据都是正确的。
常用的表单验证有:

  1. 非空验证
  2. 长度验证
  3. 数字验证
  4. 日期时间格式验证
  5. 邮箱地址验证
  6. 网址验证
  7. … …
    <h3>登陆</h3>
    <form>
     用户名:<input type="text" id="userName"><br>
     密码:<input type="password" id="password"><br>
     <input type="button" value="提交" onclick="checkForm()">
    </form>
    <script>
     function checkForm(){
         let userName = document.getElementById('userName');
         let password = document.getElementById('password');
         //用户名非空验证
         if(userName.value==''){
             alert('用户名不能为空!');
             return;
         }
         //密码非空验证
         if(password.value==''){
             alert('密码不能为空!');
             return;
         }
         //密码长度必须为六位
         if(password.value.length!=6){
             alert('密码长度必须为6位!');
             return;
         }
         //密码必须全部为数字
         if(isNaN(password.value)){
             alert('密码必须全部为数字!');
             return;
         }
         alert('提交');
     }
    </script>
    

    2.DOM编程实际案例

    2.1.时钟

    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="utf-8" />
         <title>时钟</title>
     </head>
     <body>
         <p id="myclock" style="font-size:24px"></p>
         <button id="startBtn">开始</button>
         <button id="stopBtn">停止</button>
         <script>
             let myclock = document.getElementById("myclock");
             let startBtn = document.getElementById("startBtn");
             let stopBtn = document.getElementById("stopBtn");
             callback();
             let mytimer = setInterval(callback, 1000);
             function callback() {
                 var mydate = new Date();
                 myclock.innerHTML = mydate.getHours() +
                     ":" + mydate.getMinutes() +
                     ":" + mydate.getSeconds();
             }
             //启动按钮事件
             startBtn.onclick = function() {
                 if (mytimer == null) {
                     mytimer = setInterval(callback, 1000);
                 }
             };
             //停止按钮事件
             stopBtn.onclick = function() {
                 clearInterval(mytimer);
                 mytimer = null;
             };
         </script>
     </body>
    </html>
    

    2.2.全选

    05.DOM编程 - 图4
    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="utf-8">
         <title>全选</title>
     </head>
     <body>
         全选<input class="btn" type="checkbox">
         <ul>
             <li><input type="checkbox">杜比环绕,家庭影院必备,超真实享受</li>
             <li><input type="checkbox">NVDIA 99999GT 2G 1024bit极品显卡,不容错过</li>
             <li><input type="checkbox">精品热卖,高清晰,45寸LED电视</li>
             <li><input type="checkbox">Sony索尼家用最新款笔记本</li>
             <li><input type="checkbox">华为,荣耀3C,超低价,性价比奇高</li>
         </ul>
         <script>
             let btn = document.getElementsByClassName('btn')[0];
             let inputArr = document.getElementsByTagName('ul')[0].getElementsByTagName('input');
             btn.onclick = function() {
                 let bool = btn.checked;
                 for (let i = 0; i < inputArr.length; i++) {
                     inputArr[i].checked = bool;
                 }
             }
         </script>
     </body>
    </html>
    

    2.3.图片轮播

    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="utf-8">
         <title>图片轮播</title>
         <style>
             #lunbo {
                 width: 1226px;
                 height: 460px;
                 position: relative;
                 margin: 0 auto;
             }
             #lunbo img {
                 width: 1226px;
                 height: 460px;
                 position: absolute;
                 left: 0;
                 top: 0;
                 display: none;
             }
         </style>
     </head>
     <body>
         <div id="lunbo">
             <img src="img/lunbo1.jpg">
             <img src="img/lunbo2.jpg">
             <img src="img/lunbo3.jpg">
             <img src="img/lunbo4.jpg">
             <img src="img/lunbo5.jpg">
             <img src="img/lunbo6.jpg">
         </div>
         <script>
             let imgArr = document.getElementById('lunbo').getElementsByTagName('img');
             //图片数量
             let imgNum = imgArr.length
             //用此索引来跟踪图片轮播顺序(第一张图片索引即为0)
             let index = 0;
             //初始化第一张图片
             imgArr[0].style.display = 'block';
             //每隔3秒轮播一张图片
             setInterval(function(){
                 index++;
                 //如果轮播到最后一张图片,那么索引就归零
                 if (index > imgNum - 1) {
                     index = 0;
                 }
                 //先隐藏所有图片
                 for (let i=0;i<imgNum; i++) {
                     imgArr[i].style.display = 'none';
                 }
                 //再显示当前图片
                 imgArr[index].style.display = 'block';
             }, 3000);
         </script>
     </body>
    </html>
    

    2.4.图片轮播(过渡效果)

    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="utf-8">
         <title>图片轮播(过度效果)</title>
         <style>
             #lunbo {
                 width: 1226px;
                 height: 460px;
                 position: relative;
                 margin: 0 auto;
             }
             #lunbo img {
                 width: 1226px;
                 height: 460px;
                 position: absolute;
                 left: 0;
                 top: 0;
                 opacity: 0;
                 /*display: none;*/
             }
         </style>
     </head>
     <body>
         <div id="lunbo">
             <img src="img/lunbo1.jpg">
             <img src="img/lunbo2.jpg">
             <img src="img/lunbo3.jpg">
             <img src="img/lunbo4.jpg">
             <img src="img/lunbo5.jpg">
             <img src="img/lunbo6.jpg">
         </div>
         <script>
             let imgArr = document.getElementById('lunbo').getElementsByTagName('img');
             //图片数量
             let imgNum = imgArr.length;
             //当前图片索引
             let index = 0;
             //上一张图片索引
             let preIndex = index;
             //当前图片初始透明度
             let opacityValue = 0;
             //上一张图片初始透明度
             let preOpacityValue = 1;
             //初始化第一张图片
             imgArr[index].style.opacity = 1;
             setInterval(function() {
                 //每次切换时,确定当前图片索引与上一张图片索引
                 preIndex = index;
                 index++;
                 //判断是否进行下一轮轮播
                 if (index > imgNum-1) {
                     index = 0;
                 }
                 //上一张图片隐藏
                 hideImg();
                 //当前图片显示
                 showImg();
             }, 3000);
             function showImg() {
                 //设置当前显示图片透明度初始值
                 opacityValue = 0;
                 //淡入动画
                 let time = setInterval(function() {
                     opacityValue += 0.05;
                     if (opacityValue >= 1) {
                         opacityValue = 1;
                         clearInterval(time);
                     }
                     imgArr[index].style.opacity = opacityValue;
                 }, 40);
             }
             function hideImg() {
                 //设置上一张隐藏图片透明度初始值
                 preOpacityValue = 1;
                 //淡出动画
                 let time = setInterval(function() {
                     preOpacityValue -= 0.05;
                     if (preOpacityValue <= 0) {
                         preOpacityValue = 0;
                         clearInterval(time);
                     }
                     imgArr[preIndex].style.opacity = preOpacityValue;
                 }, 40);
             }
         </script>
     </body>
    </html>
    

    2.5.放大镜

    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="utf-8">
         <title>放大镜</title>
         <style>
             #fdj {
                 position: relative;
                 width: 450px;
                 height: 450px;
             }
             #fdj img{
                 width: 450px;
                 height: 450px;
             }
             #fdj .mengban {
                 position: absolute;
                 display: none;
                 width: 225px;
                 height: 225px;
                 background-color: yellow;
                 opacity: 0.4;
                 cursor: move;
                 left: 0;
                 top: 0;
             }
             #fdj .fdjBox {
                 position: absolute;
                 width: 450px;
                 height: 450px;
                 top: 0;
                 left: 460px;
                 display: none;
             }
         </style>
     </head>
     <body>
         <!--这里是大图片-->
         <div id="fdj">
             <img src="img/dazi.jpg">
             <div class="mengban"></div>
             <div class="fdjBox"></div>
         </div>
         <script>
             <!-- onload能保证图片也加载完毕 -->
             window.onload = function() {
                 let fdj = document.getElementById('fdj');
                 let mengban = fdj.getElementsByClassName('mengban')[0];
                 let fdjBox = fdj.getElementsByClassName('fdjBox')[0];
                 //图片尺寸
                 let imgWidth = fdj.getElementsByTagName('img')[0].width;
                 fdj.onmousemove = function(event) {
                     //这里获取了蒙板的left和top(offsetLeft是fdj距离视口的位置)
                     let left = event.clientX - this.offsetLeft - imgWidth / 2 / 2;
                     let top = event.clientY - this.offsetTop - imgWidth / 2 / 2;
                     //console.log(left + ',' + top);
                     if (left < 0) {
                         left = 0;
                     }
                     if (left > this.offsetWidth - imgWidth/2) {
                         left = this.offsetWidth - imgWidth/2;
                     }
                     if (top < 0) {
                         top = 0;
                     }
                     if (top > this.offsetHeight - imgWidth/2) {
                         top = this.offsetHeight - imgWidth/2;
                     }
                     mengban.style.left = left + 'px';
                     mengban.style.top = top + 'px';
                     mengban.style.display = 'block';
                     fdjBox.style.backgroundImage = 'url(img/dazi.jpg)';
                     fdjBox.style.backgroundRepeat = 'no-repeat';
                     fdjBox.style.backgroundPosition = -left * 2 + 'px' + ' ' + -top * 2 + 'px';
                     fdjBox.style.display = 'block';
                 }
                 fdj.onmouseout = function() {
                     mengban.style.display = 'none';
                     fdjBox.style.display = 'none';
                 }
             }
         </script>
     </body>
    </html>
    

    2.6.走马灯

    <!DOCTYPE html>
    <html>
     <head>
         <meta charset="utf-8">
         <title>走马灯</title>
         <style>
             #container {
                 width: 750px;
                 height: 198px;
                 margin: 0 auto;
                 display: flex;
             }
             #container > img{
                 width: 55px;
                 height: 198px;
             }
             #container div{
                 position: relative;
                 width: 640px;
                 height: 198px;
                 overflow: hidden;
                 display: flex;
             }
             #container div ul {
                 list-style: none;
                 margin: 0;
                 padding: 0;
                 position: absolute;
                 width: 640px;
                 height: 198px;
                 left: 0px;
                 top: 0px;
                 display: flex;
             }
             #container div ul li {
                 width: 160px;
                 height: 198px;
             }
         </style>
     </head>
     <body>
         <!--图片尺寸:160*198-->
         <div id="container">
             <img src="img/left.jpg">
             <div>
                 <ul>
                     <li><a href="#"><img src="img/zmd1.jpg"></a></li>
                     <li><a href="#"><img src="img/zmd2.jpg"></a></li>
                     <li><a href="#"><img src="img/zmd3.jpg"></a></li>
                     <li><a href="#"><img src="img/zmd4.jpg"></a></li>
                 </ul>
             </div>
             <img src="img/right.jpg">
         </div>
         <script>
             window.onload = function() {
                 let container = document.getElementById('container');
                 let scoll = container.getElementsByTagName("ul")[0];
                 let imgArr = document.querySelectorAll('#container > img');
                 let btnLeft = imgArr[0];
                 let btnRight = imgArr[1];
                 //滚动速度
                 let speed = 5;
                 //滚动方向(初始向右)
                 let fangxiang = 1;
                 //获取图片数量
                 let imgNum = scoll.getElementsByTagName("img").length;
                 //获取图片宽度
                 let imgWidth = scoll.getElementsByTagName("img")[0].width;
                 //获取滚动条宽度
                 let scollWidth = imgNum * imgWidth;
                 //给滚动条加一倍的内容
                 scoll.style.width = scollWidth * 2 + "px";
                 scoll.innerHTML += scoll.innerHTML;
                 //滚动条初始位置
                 scoll.style.left = "-" + scollWidth + "px";
                 let myTimer = setInterval(gundong, 40);
                 function gundong() {
                     if (fangxiang == 1) {
                         if (scoll.offsetLeft >= 0) {
                             scoll.style.left = "-" + scollWidth + "px";
                         }
                     } else {
                         if (scoll.offsetLeft <= scollWidth * -1) {
                             scoll.style.left = 0 + "px";
                         }
                     }
                     scoll.style.left = scoll.offsetLeft + (speed * fangxiang) + "px";
                 }
                 btnLeft.onmouseover = function() {
                     fangxiang = -1;
                 };
                 btnRight.onmouseover = function() {
                     fangxiang = 1;
                 };
                 scoll.onmouseover = function() {
                     clearInterval(myTimer);
                 }
                 scoll.onmouseout = function() {
                     myTimer = setInterval(gundong, 40);
                 }
             }
         </script>
     </body>
    </html>