当前位置: 首页 > article >正文

JS中DOM和BOM

DOM

DOM(文档对象模型)是一个跨平台和语言独立的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。在网页浏览器中,DOM 通常表示 HTML 或 XML 文档的对象模型。DOM 将网页内容视为节点树,其中每个节点都是文档中的对象,例如元素、属性、文本等。

以下是 DOM 的一些关键点:

  • 文档:在 Web 浏览器中,文档通常是指网页,即 HTML 或 XML 文件。

  • 对象模型:对象模型是将文档内容表示为对象集合的一种方式,这些对象可以由程序代码进行操作。

  • 节点树:DOM 将文档结构表示为节点树,树中的每个节点代表文档的一部分。例如,HTML 文档中的每个元素、属性和文本都是节点。

  • 编程接口:DOM 提供了一组方法(函数)和属性(变量),允许开发人员通过 JavaScript(或其他支持的语言)操作文档。

 DOM中的节点类型

在 DOM(文档对象模型)中,节点类型是通过 nodeType 属性来区分的,每个节点类型都有一个对应的常量值。以下是一些主要的 DOM 节点类型及其对应的常量值:

  1. 元素节点(Element Node)

    • 常量值:Node.ELEMENT_NODE
    • 整数值:1
    • 示例:<div><p><a>
  2. 属性节点(Attribute Node)

    • 常量值:Node.ATTRIBUTE_NODE
    • 整数值:2
    • 示例:href in <a href="http://example.com">
  3. 文本节点(Text Node)

    • 常量值:Node.TEXT_NODE
    • 整数值:3
    • 示例:文本内容 “Hello, World!” in <p>Hello, World!</p>
  4. CDATA 节点(CDATASection Node)

    • 常量值:Node.CDATA_SECTION_NODE
    • 整数值:4
    • 示例:<![CDATA[...]]> in XML documents
  5. 实体引用节点(EntityReference Node)

    • 常量值:Node.ENTITY_REFERENCE_NODE
    • 整数值:5
    • 注:在 HTML DOM 中不常用
  6. 实体节点(Entity Node)

    • 常量值:Node.ENTITY_NODE
    • 整数值:6
    • 注:在 HTML DOM 中不常用
  7. 处理指令节点(ProcessingInstruction Node)

    • 常量值:Node.PROCESSING_INSTRUCTION_NODE
    • 整数值:7
    • 示例:处理指令,常用于 XML
  8. 注释节点(Comment Node)

    • 常量值:Node.COMMENT_NODE
    • 整数值:8
    • 示例:<!-- This is a comment -->
  9. 文档节点(Document Node)

    • 常量值:Node.DOCUMENT_NODE
    • 整数值:9
    • 示例:整个 HTML 或 XML 文档
  10. 文档类型节点(DocumentType Node)

    • 常量值:Node.DOCUMENT_TYPE_NODE
    • 整数值:10
    • 示例:<!DOCTYPE html>
  11. 文档片段节点(DocumentFragment Node)

    • 常量值:Node.DOCUMENT_FRAGMENT_NODE
    • 整数值:11
    • 示例:轻量级的文档对象,可以包含多个元素而不影响文档结构
  12. 符号节点(Notation Node)

    • 常量值:Node.NOTATION_NODE
    • 整数值:12
    • 注:在 HTML DOM 中不常用

一、节点的创建、移除和克隆

1.如何改变元素节点中的内容

改变元素节点中的内容可以使用两个相关属性:innerHTML、innerText。innerHTML属性能以HTML形式设置节点中的内容;innerText系统属性只能以纯文本的形式设置节点中的内容。

2.创建节点

想要两步,第一步使用document.createElement()创建节点,第二步再上树,上树有两种情况,如果是在添加在最后,那就使用appendChild();如果不是,使用insertBefore。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="box">
        <p>我是原本的段落0</p>
        <p>我是原本的段落1</p>
        <p>我是原本的段落2</p>
    </div>
    <script>
        var oBox = document.getElementById('box');
        var oPs = oBox.getElementsByTagName('p');

        // 创建孤儿节点
        var oP = document.createElement('p');
        // 设置内部文字
        oP.innerText = '我是新来的';
        
        // 上树
        // oBox.appendChild(oP);
        oBox.insertBefore(oP, oPs[0]);
    </script>
</body>

</html>

创建出一个20行12列的表格

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        td {
            width: 20px;
            height: 20px;
            border: 1px solid #000;
        }
    </style>
</head>

<body>
    <table id="mytable"></table>

    <script>
        // 请动态创建出一个20行12列的表格
        var mytable = document.getElementById('mytable');

        for (var i = 0; i < 20; i++) {
            // 创建了新的tr标签
            var tr = document.createElement('tr');
            for (var j = 0; j < 12; j++) {
                // 创建了新的td标签
                var td = document.createElement('td');
                // 让tr追加td标签
                tr.appendChild(td);
            }
            // 让mytable追加tr标签
            mytable.appendChild(tr);
        }
    </script>
</body>

</html>

创建9*9乘法表

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        td {
            width: 120px;
            height: 30px;
            border: 1px solid #000;
        }
    </style>
</head>

<body>
    <table id="mytable"></table>

    <script>
        // 请创建九九乘法表
        var mytable = document.getElementById('mytable');

        for (var i = 1; i <= 9; i++) {
            // 创建了新的tr标签
            var tr = document.createElement('tr');
            for (var j = 1; j <= i; j++) {
                // 创建了新的td标签
                var td = document.createElement('td');
                // 设置td内部的文字
                td.innerText = i + '乘' + j + '等于' + (i * j);
                // 让tr追加td标签
                tr.appendChild(td);
            }
            // 让mytable追加tr标签
            mytable.appendChild(tr);
        }
    </script>
</body>

</html>

 3.移动节点

如果将已经挂载到DOM树上的节点成为appendChild()或者insertBefore()的参数,这个节点将被移动。新父节点.appendChild(已经有父亲的节点);新父节点.insertBefore(已经有父亲的节点,标杆子节点);这意味着一个节点不能同时位于DOM树的两个位置。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="box1">
        <p id="para">我是段落</p>
    </div>

    <div id="box2">
        <p>我是box2的原有p标签</p>
        <p>我是box2的原有p标签</p>
        <p>我是box2的原有p标签</p>
        <p>我是box2的原有p标签</p>
    </div>

    <script>
        var box1 = document.getElementById('box1');
        var box2 = document.getElementById('box2');
        var para = document.getElementById('para');
        var ps_inbox2 = box2.getElementsByTagName('p');

        // box2.appendChild(para);
        box2.insertBefore(para, ps_inbox2[0]);
    </script>
</body>
</html>

4.删除节点

removeChild()方法从DOM中删除一个字节点 父节点.removeChild(要删除子节点);子节点不能主动删除自己,必须由父节点删除它。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="box">
        <p>我是p节点0</p>
        <p>我是p节点1</p>
        <p>我是p节点2</p>
    </div>

    <script>
        var box = document.getElementById('box');
        var the_first_p = box.getElementsByTagName('p')[0];

        box.removeChild(the_first_p);
    </script>
</body>
</html>

5.克隆节点

cloneNode()方法可以克隆节点,克隆出的节点上“孤儿节点”。

var 孤儿节点=老节点.cloneNode();

var 孤儿节点=老节点.cloneNode(true);

参数是一个布尔值,表示是否采用深度克隆;如果为true,则该节点的所有后代节点也都会被克隆,如果为false,则只克隆该节点本身。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="box1">
        <ul>
            <li>牛奶</li>
            <li>咖啡</li>
            <li>可乐</li>
        </ul>
    </div>

    <div id="box2"></div>

    <script>
        var box1 = document.getElementById('box1');
        var box2 = document.getElementById('box2');
        var theul = box1.getElementsByTagName('ul')[0];

        // 克隆节点
        var new_ul = theul.cloneNode(true);
        box2.appendChild(new_ul);
    </script>
</body>
</html>

6.JS修改样式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box{
            width: 200px;
            height: 200px;
            border: 1px solid #000;
        }
    </style>
</head>
<body>
    <div class="box" id="box">
        你好
    </div>

    <script>
        var oBox = document.getElementById('box');

        // oBox.style.backgroundColor = 'rgb(100, 200, 123)';
        // oBox.style.backgroundColor = '#f80';

        // oBox.style.backgroundImage = 'url(https://www.imooc.com/static/img/index/logo-recommended.png)';
        // oBox.style.backgroundSize = 'contain';

        oBox.style.fontSize = '50px';
    </script>
</body>
</html>

 7.nodeType常用属性值

8.访问元素节点

注意:如果有多个id相同的元素 只能找到第一个。 无论id多深,都能找到。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <div id="box1">我是盒子1</div>
    <div id="box2">我是盒子2</div>

    <script>
        
            // 得到盒子1
            var box1 = document.getElementById('box1');
            // 得到盒子2
            var box2 = document.getElementById('box2');

            console.log(box1);
            console.log(box2);
        
    </script>
</body>

</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="box1">
        <p>我是段落</p>
        <p>我是段落</p>
        <p>我是段落</p>
        <p>我是段落</p>
    </div>
    <div id="box2">
        <p>我是段落</p>
        <p>我是段落</p>
        <p>我是段落</p>
        <p>我是段落</p>
    </div>
   
    <script>
        // 先得到box1
        var box1 = document.getElementById('box1');
        // 得到box1中的p标签的数组
        var ps_inbox1 = box1.getElementsByTagName('p');

        console.log(ps_inbox1);
    </script>
</body>
</html>

9.延迟运行

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        // 给window对象添加onload事件监听。onload表示页面都加载完毕了。
        window.onload = function () {
            // 得到盒子1
            var box1 = document.getElementById('box1');
            // 得到盒子2
            var box2 = document.getElementById('box2');

            console.log(box1);
            console.log(box2);
        };
    </script>
</head>

<body>
    <div id="box1">我是盒子1</div>
    <div id="box2">我是盒子2</div>
</body>

</html>

 10.querySelector()

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="box">
        <p>我是段落</p>
        <p class="spec para">我是段落</p>
        <p>我是段落</p>
    </div>
    <script>
        var the_p = document.querySelector('#box p:nth-child(1)');
        console.log(the_p);
        
    </script>
</body>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <ul id="list1">
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
    </ul>
    <ul id="list2">
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
    </ul>
    <script>
        var lis_inlist1 = document.querySelectorAll('#list1 li');

        console.log(lis_inlist1);
    </script>
</body>
</html>

11.节点的关系

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="box">
        <p>我是段落A</p>
        <p id="para">我是段落B</p>
        <p>我是段落C</p>
    </div>

    <script>
        var box = document.getElementById('box');
        var para = document.getElementById('para');

        // 所有子节点
        console.log(box.childNodes);
        // 所有的元素子节点(IE9开始兼容)
        console.log(box.children);
        
        // 第一个子节点
        console.log(box.firstChild);
        console.log(box.firstChild.nodeType);//子节点的类型,它是一个数
        // 第一个元素子节点(IE9开始兼容)
        console.log(box.firstElementChild);
        
        // 最后一个子节点
        console.log(box.lastChild);
        console.log(box.lastChild.nodeType);//子节点的类型,它是一个数
        // 最后一个元素子节点(IE9开始兼容)
        console.log(box.lastElementChild);

        // 父节点
        console.log(para.parentNode);
        
        // 前一个兄弟节点
        console.log(para.previousSibling);
        // 前一个元素兄弟节点(IE9开始兼容)
        console.log(para.previousElementSibling);
        
        // 后一个兄弟节点
        console.log(para.nextSibling);
        // 后一个元素兄弟节点(IE9开始兼容)
        console.log(para.nextElementSibling);
    </script>
</body>
</html>

12.常见的节点关系函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="box">
        <p>我是段落</p>
        <p>我是段落</p>
        <p>我是段落</p>
        <p id="fpara">我是段落fpara</p>
        我是文本
        <!-- 我是注释 -->
        <p id="para">
            我是段落para
            <span>1</span>
            <span>2</span>
            <span>3</span>
        </p>
        <p>我是段落</p>
        <p>我是段落</p>
        <p>我是段落</p>
    </div>

    <script>
        var box = document.getElementById('box');
        var para = document.getElementById('para');
        var fpara = document.getElementById('fpara');

        // 封装一个函数,这个函数可以返回元素的所有子元素节点(兼容到IE6),类似children的功能
        function getChildren(node) {
            // 结果数组
            var children = [];
            // 遍历node这个节点的所有子节点,判断每一个子节点的nodeType属性是不是1
            // 如果是1,就推入结果数组
            for (var i = 0; i < node.childNodes.length; i++) {
                if (node.childNodes[i].nodeType == 1) {
                    children.push(node.childNodes[i]);
                }
            }
            return children;
        }

        console.log(getChildren(box));
        console.log(getChildren(para));

        // 封装一个函数,这个函数可以返回元素的前一个元素兄弟节点(兼容到IE6),类似previousElementSibling的功能
        function getElementPrevSibling(node) {
            var o = node;
            // 使用while语句
            while (o.previousSibling != null) {
                if (o.previousSibling.nodeType == 1) {
                    // 结束循环,找到了
                    return o.previousSibling;
                }

                // 让o成为它的前一个节点,就有点“递归”的感觉
                o = o.previousSibling;
            }
            return null;
        }

        console.log(getElementPrevSibling(para));
        console.log(getElementPrevSibling(fpara));

        // 封装第三个函数,这个函数可以返回元素的所有元素兄弟节点
        function getAllElementSibling(node) {
            // 前面的元素兄弟节点
            var prevs = [];
            // 后面的元素兄弟节点
            var nexts = [];
            
            var o = node;
            // 遍历node的前面的节点
            while(o.previousSibling != null) {
                if(o.previousSibling.nodeType == 1){
                    prevs.unshift(o.previousSibling);
                }
                o = o.previousSibling;
            }

            o = node;

            // 遍历node的后面的节点
            while(o.nextSibling != null) {
                if(o.nextSibling.nodeType == 1){
                    nexts.push(o.nextSibling);
                }
                o = o.nextSibling;
            }

            // 将两个数组进行合并,然后返回
            return prevs.concat(nexts);
        }

        console.log(getAllElementSibling(para));
    </script>
</body>

</html>

二、DOM事件

事件监听、事件传播、事件对象、事件委托

1. 事件监听

1.常见的鼠标事件监听

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            width: 200px;
            height: 200px;
            background-color: #333;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    
    <script>
        var oBox = document.getElementById('box');

        oBox.onclick = function() {
            console.log('我是onclick');
        };

        oBox.ondblclick = function() {
            console.log('我是ondblclick');
        };

        oBox.onmousedown = function() {
            console.log('我是onmousedown');
        };

        oBox.onmouseup = function() {
            console.log('我是onmouseup');
        };

        oBox.onmouseenter = function() {
            console.log('我是onmouseenter');
        };

        oBox.onmouseleave = function() {
            console.log('我是onmouseleave');
        };

        oBox.onmousemove = function() {
            console.log('我是onmousemove');
        };
    </script>
</body>
</html>

2.常见的键盘事件监听

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    姓名:
    <input type="text" id="nameField">

    <script>
        var nameField = document.getElementById('nameField');

        nameField.onkeydown = function () {
            console.log('我是onkeydown');
        };

        nameField.onkeypress = function() {
            console.log('我是onkeypress');
        }

        nameField.onkeyup = function() {
            console.log('我是onkeyup');
        }
    </script>
</body>
</html>

3.事件传播

事件传播是:先从外到内,再从内到外。

(1)onxxx写法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box1{
            width: 202px;
            height: 202px;
            border: 1px solid #000;
            padding: 50px;
        }
        #box2{
            width: 100px;
            height: 100px;
            border: 1px solid #000;
            padding: 50px;
        }
        #box3{
            width: 100px;
            height: 100px;
            border: 1px solid #000;
        }
    </style>
</head>
<body>
    <div id="box1">
        <div id="box2">
            <div id="box3"></div>
        </div>
    </div>
    <script>
        var oBox1 = document.getElementById('box1');
        var oBox2 = document.getElementById('box2');
        var oBox3 = document.getElementById('box3');

        oBox2.onclick = function () {
            console.log('我是box2的onclick');
        };

        oBox3.onclick = function () {
            console.log('我是box3的onclick');
        };

        oBox1.onclick = function () {
            console.log('我是box1的onclick');
        };
    </script>
</body>
</html>
(2) addEventListener()方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box1{
            width: 202px;
            height: 202px;
            border: 1px solid #000;
            padding: 50px;
        }
        #box2{
            width: 100px;
            height: 100px;
            border: 1px solid #000;
            padding: 50px;
        }
        #box3{
            width: 100px;
            height: 100px;
            border: 1px solid #000;
        }
    </style>
</head>
<body>
    <div id="box1">
        <div id="box2">
            <div id="box3"></div>
        </div>
    </div>
    <script>
        var oBox1 = document.getElementById('box1');
        var oBox2 = document.getElementById('box2');
        var oBox3 = document.getElementById('box3');

      

        oBox2.addEventListener('click', function() {
            console.log('我是box2的冒泡阶段');
        }, false);
      
      
        oBox3.addEventListener('click', function() {
            console.log('我是box3的捕获阶段');
        }, true);

        oBox3.addEventListener('click', function() {
            console.log('我是box3的冒泡阶段');
        }, false);

        oBox3.onclick = function () {
            console.log('我是box3的onclick');
        };

        oBox1.addEventListener('click', function() {
            console.log('我是box1的冒泡阶段');
        }, false);

        oBox2.addEventListener('click', function() {
            console.log('我是box2的捕获阶段');
        }, true);

        oBox1.addEventListener('click', function() {
            console.log('我是box1的捕获阶段');
        }, true);

        oBox1.onclick = function () {
            console.log('我是box1的onclick');
        };

        oBox2.onclick = function () {
            console.log('我是box2的onclick');
        };

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

4.事件对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        #box{
            width: 200px;
            height: 200px;
            background-color: #333;
            margin: 100px;
        }
        body{
            height: 2000px;
        }
        #info{
            font-size: 30px;
        }
         
    </style>
</head>
<body>
    <div id="box">
         
    </div>
    <div id="info"></div>

    <script>
        var oBox = document.getElementById('box');
        var oInfo = document.getElementById('info');

        oBox.onmousemove = function (e) {
            oInfo.innerHTML = 'offsetX/Y:' + e.offsetX + ',' + e.offsetY + '<br>'
                            + 'clientX/Y:' + e.clientX + ',' + e.clientY + '<br>'
                            + 'pageX/Y:' + e.pageX + ',' + e.pageY;
        };
    </script>
</body>
</html>

5.charCode和keyCode

demo:按键使盒子移动

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box {
            position: absolute;
            top: 200px;
            left: 200px;
            width: 100px;
            height: 100px;
            background-color: orange;
        }
    </style>
</head>

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

    <script>
        var oBox = document.getElementById('box');

        // 全局变量t、l,分别表示盒子的top属性值和left属性值
        var t = 200;
        var l = 200;

        // 监听document对象的键盘按下事件监听,表示当用户在整个网页上按下按键的时候
        document.onkeydown = function (e) {
            switch (e.keyCode) {
                case 37:
                    l -= 3;
                    break;
                case 38:
                    t -= 3;
                    break;
                case 39:
                    l += 3;
                    break;
                case 40:
                    t += 3;
                    break;
            }

            // 更改样式
            oBox.style.left = l + 'px';
            oBox.style.top = t + 'px';
        };
    </script>
</body>

</html>

 6.e.preventDefault()方法

Demo1:阻止文本框的默认行为(默认是敲一个字母就会在文本框里显示,现在阻止这种行为)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <p>
        只能输入小写字母和数字:
        <input type="text" id="field">
    </p>
    <script>
        var oField = document.getElementById('field');

        oField.onkeypress = function (e) {
            console.log(e.charCode);
            
            // 根据用户输入的字符的字符码(e.charCode)
            // 数字0~9,字符码48~57
            // 小写字母a~z,字符码97~122
            if (!(e.charCode >= 48 && e.charCode <= 57 || e.charCode >= 97 && e.charCode <= 122)) {
                // 阻止浏览器的默认行为
                e.preventDefault();
            }
        };
    </script>
</body>

</html>

 Demo2:制作鼠标滚轮事件:当鼠标在盒子中向下滚动时,数字+1;反之,数字-1。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box {
            width: 200px;
            height: 200px;
            background-color: #333;
        }
        body{
            height: 2000px;
        }
    </style>
</head>

<body>
    <div id="box"></div>
    <h1 id="info">0</h1>

    <script>
        var oBox = document.getElementById('box');
        var oInfo = document.getElementById('info');

        // 全局变量就是info中显示的数字
        var a = 0;

        // 给box盒子添加鼠标滚轮事件监听
        oBox.onmousewheel = function (e) {
            // 阻止默认事件:就是说当用户在盒子里面滚动鼠标滚轮的时候,此时不会引发页面的滚动条的滚动
            e.preventDefault();
            
            if (e.deltaY > 0) {
                a++;
            } else {
                a--;
            }
            oInfo.innerText = a;
        }
    </script>
</body>

</html>

 7.stopPropagation()方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            width: 200px;
            height: 200px;
            background-color: #333;
        }
    </style>
</head>

<body>
    <div id="box">
        <button id="btn">按我</button>
    </div>
    <script>
        var oBox = document.getElementById('box');
        var oBtn = document.getElementById('btn');

        // oBox.onclick = function () {
        //     console.log('我是盒子');
        // };

        // oBtn.onclick = function (e) {
        //     阻止事件继续传播
        //     e.stopPropagation();
        //     console.log('我是按钮');
        // };

        oBox.addEventListener('click', function(e) {
            // 阻止事件继续传播
            e.stopPropagation();
            console.log('我是盒子');
        }, true)//true代表捕获阶段

        oBtn.addEventListener('click', function() {
            console.log('我是按钮');
        }, true);
    </script>
</body>

</html>

Demo:制造弹出层

制作一个弹出层,点击按钮显示弹出层,点击网页除它自身外的任意地方,弹出层关闭。

如果不去阻止事件传播,会点击按钮的瞬间就关闭,因为按钮也是网页的任意地方。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .modal {
            width: 400px;
            height: 140px;
            background-color: #333;
            position: absolute;
            top: 50%;
            left: 50%;
            margin-top: -70px;
            margin-left: -200px;
            display: none;
        }
    </style>
</head>

<body>
    <button id="btn">按我弹出弹出层</button>
    <div class="modal" id="modal"></div>

    <script>
        var oBtn = document.getElementById('btn');
        var oModal = document.getElementById('modal');

        // 点击按钮的时候,弹出层显示
        oBtn.onclick = function (e) {
            // 阻止事件继续传播到document身上
            e.stopPropagation();
            oModal.style.display = 'block';
        };

        // 点击页面任何部分的时候,弹出层关闭
        document.onclick = function () {
            oModal.style.display = 'none';
        };

        // 点击弹出层内部的时候,不能关闭弹出层的,所以应该阻止事件继续传播
        oModal.onclick = function (e) {
            // 阻止事件继续传播到document身上
            e.stopPropagation();
        };
    </script>
</body>

</html>

8.事件委托

什么是事件委托?

事件委托(Event Delegation)是一种在JavaScript中处理事件的技术,它利用了事件冒泡的原理。在事件冒泡的过程中,事件会从触发它的最深层节点开始,然后逐级向上传播至文档的根节点。事件委托的核心思想是,不必为每一个子节点单独绑定事件处理器,而是将事件处理器绑定到它们的共同祖先节点上,利用事件冒泡,当事件发生时,会冒泡到祖先节点,然后在该祖先节点上根据事件的目标元素(event.target)来决定如何处理事件。

事件委托的几个主要优点如下:

  1. 性能优化:减少了需要绑定事件处理器的元素数量,从而减少了内存的使用,并可能提高页面的加载速度。

  2. 动态内容:对于动态添加的元素,无需再次绑定事件处理器,因为事件处理器已经绑定在它们的祖先元素上。

  3. 简化代码:减少了代码的复杂性和冗余,使得代码更加简洁。

下面是一个简单的例子来说明事件委托:

// 假设有一个列表,我们想为列表中的每个项目添加点击事件
<ul id="list">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <!-- 可能还有更多的列表项 -->
</ul>

// 我们可以为ul元素绑定一个点击事件,而不是为每个li元素绑定
document.getElementById('list').addEventListener('click', function(event) {
    // 检查事件的目标元素是否是li
    if (event.target.tagName === 'LI') {
        // 如果是,执行相应的操作
        console.log('List item clicked:', event.target.textContent);
    }
});

在上面的例子中,不管列表中有多少个<li>元素,甚至如果以后动态添加了更多的<li>元素,我们都不需要为它们单独绑定事件处理器。点击任何<li>元素都会触发绑定在<ul>上的事件处理器,处理器会检查事件的目标元素,如果是<li>,则执行相关操作。这就是事件委托的基本用法。

什么时候使用事件委托?

事件委托通常在以下几种情况下使用:

  1. 动态内容:当你需要为动态添加到DOM中的元素绑定事件时,事件委托非常有用。由于事件处理器绑定在父元素上,新添加的子元素无需再次绑定事件。

  2. 大量元素:当页面上有大量的元素需要绑定相同的事件处理器时,事件委托可以减少内存的使用,并提高性能。

  3. 事件冒泡:当你希望利用事件冒泡的特性来减少事件监听器的数量时,可以使用事件委托。

  4. 简化代码:事件委托可以减少代码量,使得代码更加简洁和易于管理。

以下是具体的使用场景:

  • 表格行点击:在一个表格中,你可能想要在点击任意一行时触发一个事件。通过将事件处理器绑定到<table>元素上,并检查event.target是否是<tr>元素,可以实现这一点。

  • 菜单项点击:在一个菜单列表中,每个菜单项都需要绑定点击事件。通过将事件处理器绑定到<ul><nav>元素上,可以轻松管理事件。

  • 表单输入处理:在表单中,你可能想要在用户输入时执行某些操作,如即时验证。可以将事件处理器绑定到<form>元素上,并根据event.target的类型(如<input>)来执行不同的操作。

  • 拖放操作:在实现拖放功能时,可以在容器元素上设置事件监听器,而不是在每个可拖动的元素上设置。

以下是一个简单的示例,说明在动态内容情况下如何使用事件委托:

// 假设有一个空的列表,我们将动态添加列表项
<ul id="list"></ul>

// 动态添加一些列表项
function addItem(text) {
    const li = document.createElement('li');
    li.textContent = text;
    document.getElementById('list').appendChild(li);
}

// 使用事件委托绑定点击事件
document.getElementById('list').addEventListener('click', function(event) {
    if (event.target.tagName === 'LI') {
        console.log('List item clicked:', event.target.textContent);
    }
});

// 添加一些列表项
addItem('Item 1');
addItem('Item 2');
addItem('Item 3');

在上面的例子中,不管何时添加新的列表项,点击它们都会触发绑定在<ul>上的事件处理器,因为事件会冒泡到父元素,并由事件委托处理。

Demo1:批量添加点击事件监听

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul id="list">
        <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>列表项</li>
        <li>列表项</li>
    </ul>

    <script>
        var oList = document.getElementById('list');
        var lis = oList.getElementsByTagName('li');

        // 书写循环语句,批量给元素添加监听
        for (var i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                // 在这个函数中,this表示点击的这个元素,this涉及函数上下文的相关知识,我们在“面向对象”课程中介绍
                this.style.color = 'red';
            };
        }
    </script>
</body>

</html>

 Demo2:新增元素动态绑定事件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn">按我添加新的li列表项</button>
    <ul id="list"></ul>

    <script>
        var oBtn = document.getElementById('btn');
        var oList = document.getElementById('list');
        var lis = oList.getElementsByTagName('li');

        // 按钮的点击事件
        oBtn.onclick = function () {
            // 创建一个新的li列表项,孤儿节点
            var oLi = document.createElement('li');
            oLi.innerHTML = '我是列表项';
            // 上树
            oList.appendChild(oLi);
            // 给新创建的这个li节点添加onclick事件监听
            oLi.onclick = function () {
                this.style.color = 'red';
            };
        };
    </script>
</body>

</html>

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn">按我创建一个新列表项</button>
    <ul id="list">
        <li>列表项</li>
        <li>列表项</li>
        <li>列表项</li>
    </ul>
    <script>
        var oList = document.getElementById('list');
        var oBtn = document.getElementById('btn');

        oList.onclick = function (e) {
            // e.target表示用户真正点击的那个元素
            e.target.style.color = 'red';
        };

        oBtn.onclick = function () {
            // 创建新的li元素
            var oLi = document.createElement('li');
            // 写内容
            oLi.innerText = '我是新来的';
            // 上树
            oList.appendChild(oLi);
        };
    </script>
</body>

</html>

Demo3:注意事件是不是冒泡
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn">按我创建一个新列表项</button>
    <ul id="list">
        <li>列表项</li>
        <li>列表项</li>
        <li>列表项</li>
    </ul>
    <script>
        var oList = document.getElementById('list');
        var oBtn = document.getElementById('btn');

        // onmouseenter这个属性天生就是“不冒泡”的,相当于你事件处理函数附加给了哪个DOM节点
        // 就是哪个DOM节点自己触发的事件,没有冒泡过程
        oList.onmouseover = function (e) {
            // e.target表示用户真正点击的那个元素
            e.target.style.color = 'red';
        };

        oBtn.onclick = function () {
            // 创建新的li元素
            var oLi = document.createElement('li');
            // 写内容
            oLi.innerText = '我是新来的';
            // 上树
            oList.appendChild(oLi);
        };
    </script>
</body>

</html>

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box {
            position: absolute;
            top: 100px;
            left: 100px;
            width: 100px;
            height: 100px;
            background-color: orange;
        }
    </style>
</head>

<body>
    <button id="btn">开始运动</button>
    <div id="box"></div>

    <script>
        // 得到元素
        var btn = document.getElementById('btn');
        var box = document.getElementById('box');

        // 全局变量盒子的left值
        var left = 100;

        // 按钮监听
        btn.onclick = function () {
            var timer = setInterval(function () {
                // 改变全局变量
                left += 10;
                if (left >= 1000) {
                    clearInterval(timer);
                }
                // 设置left属性
                box.style.left = left + 'px';
            }, 20);
        };
    </script>
</body>

</html>

三、实现动画

1.定时器

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        var a = 0;
        
        setInterval(function () {
            console.log(++a);
        }, 1000);
    </script>
</body>

</html>

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1 id="info">0</h1>
    <button id="btn1">开始</button>
    <button id="btn2">暂停</button>

    <script>
        var oInfo = document.getElementById('info');
        var oBtn1 = document.getElementById('btn1');
        var oBtn2 = document.getElementById('btn2');

        var a = 0;

        // 全局变量
        var timer;

        oBtn1.onclick = function () {
            // 为了防止定时器叠加,我们应该在设置定时器之前先清除定时器
            clearInterval(timer);
            // 更改全局变量timer的值为一个定时器实体
            timer = setInterval(function () {
                oInfo.innerText = ++a;
            }, 1000);
        };

        oBtn2.onclick = function () {
            clearInterval(timer);
        };
    </script>
</body>

</html>

2.延时器

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="btn1">2秒后弹出你好</button>
    <button id="btn2">取消弹出</button>

    <script>
        var btn1 = document.getElementById('btn1');
        var btn2 = document.getElementById('btn2');
        var timer;

        btn1.onclick = function() {
            timer = setTimeout(function () {
                alert('你好');
            }, 2000);
        }
        
        btn2.onclick = function() {
            clearTimeout(timer);
        }
    </script>
</body>

</html>

3.使用定时器实现动画

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box {
            position: absolute;
            top: 100px;
            left: 100px;
            width: 100px;
            height: 100px;
            background-color: orange;
        }
    </style>
</head>

<body>
    <button id="btn">开始运动</button>
    <div id="box"></div>

    <script>
        // 得到元素
        var btn = document.getElementById('btn');
        var box = document.getElementById('box');

        // 全局变量盒子的left值
        var left = 100;

        // 按钮监听
        btn.onclick = function () {
            var timer = setInterval(function () {
                // 改变全局变量
                left += 10;
                if (left >= 1000) {
                    clearInterval(timer);
                }
                // 设置left属性
                box.style.left = left + 'px';
            }, 20);
        };
    </script>
</body>

</html>

4.JS和CSS3结合实现动画、函数节流公式

Demo1

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #box {
            width: 100px;
            height: 100px;
            background-color: orange;
            position: absolute;
            top: 100px;
            left: 100px;
        }
    </style>
</head>

<body>
    <button id="btn">按我运动</button>
    <div id="box"></div>

    <script>
        // 得到元素
        var btn = document.getElementById('btn');
        var box = document.getElementById('box');

        // 标识量,指示当前盒子在左边还是右边
        var pos = 1;    // 1左边,2右边

        // 函数节流锁
        var lock = true;

        // 事件监听
        btn.onclick = function () {
            // 首先检查锁是否是关闭
            if (!lock) return;

            // 把过渡加上
            box.style.transition = 'all 2s linear 0s';
            if (pos == 1) {
                // 瞬间移动,但是由于有过渡,所以是动画
                box.style.left = '1100px';
                pos = 2;
            } else if (pos == 2) {
                // 瞬间移动,但是由于有过渡,所以是动画
                box.style.left = '100px';
                pos = 1;
            }

            // 关锁
            lock = false;
            // 指定时间后,将锁打开
            setTimeout(function() {
                lock = true;
            }, 2000);
        };
    </script>
</body>

</html>

函数节流公式

5.动画效果开发1 - 无缝连续滚动特效

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .box {
            width: 1000px;
            height: 130px;
            border: 1px solid #000;
            margin: 50px auto;
            overflow: hidden;
        }

        .box ul {
            list-style: none;
            /* 设置大一点,这样li才能浮动 */
            width: 5000px;
            position: relative;
        }

        .box ul li {
            float: left;
            margin-right: 10px;
        }
    </style>
</head>

<body>
    <div id="box" class="box">
        <ul id="list">
            <li><img src="images/number/0.png" alt=""></li>
            <li><img src="images/number/1.png" alt=""></li>
            <li><img src="images/number/2.png" alt=""></li>
            <li><img src="images/number/3.png" alt=""></li>
            <li><img src="images/number/4.png" alt=""></li>
            <li><img src="images/number/5.png" alt=""></li>
        </ul>
    </div>
    <script>
        var box = document.getElementById('box');
        var list = document.getElementById('list');

        // 复制多一遍所有的li
        list.innerHTML += list.innerHTML;

        // 全局变量,表示当前list的left值
        var left = 0;

        // 定时器,全局变量
        var timer;

        move();

        // 动画封装成函数
        function move() {
            // 设表先关,防止动画积累
            clearInterval(timer);

            timer = setInterval(function () {
                left -= 4;
                // 验收
                // 这个1250是每个图片的宽度是200,6个图片循环,然后有6个边距10px(最后一个边距是为了衔接自然),所以总结就是200*6+6*10=1260
                if (left <= - 1260) {
                    left = 0;
                }
                list.style.left = left + 'px';
            }, 20);
        }

        // 鼠标进入停止定时器
        box.onmouseenter = function () {
            clearInterval(timer);
        };

        // 鼠标离开继续定时器
        box.onmouseleave = function () {
            move();
        };
    </script>
</body>

</html>

6.动画效果开发2 - 跑马灯轮播图特效

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .carousel {
            width: 650px;
            height: 360px;
            border: 1px solid #000;
            margin: 50px auto;
            position: relative;
            overflow: hidden;
        }
        .carousel ul {
            list-style: none;
            width: 6000px;
            position: relative;
            left: 0px;
            transition: left .5s ease 0s;
        }
        .carousel ul li {
            float: left;
        }
        .carousel .leftbtn {
            position: absolute;
            left: 20px;
            top: 50%;
            margin-top: -25px;
            width: 50px;
            height: 50px;
            background-color: rgb(28, 180, 226);
            border-radius: 50%;
        }
        .carousel .rightbtn {
            position: absolute;
            right: 20px;
            top: 50%;
            margin-top: -25px;
            width: 50px;
            height: 50px;
            background-color: rgb(28, 180, 226);
            border-radius: 50%;
        }
    </style>
</head>
<body>
    <div class="carousel">
        <ul id="list">
            <li><img src="images/beijing/0.jpg" alt=""></li>
            <li><img src="images/beijing/1.jpg" alt=""></li>
            <li><img src="images/beijing/2.jpg" alt=""></li>
            <li><img src="images/beijing/3.jpg" alt=""></li>
            <li><img src="images/beijing/4.jpg" alt=""></li>
        </ul>
        <a href="javascript:;" class="leftbtn" id="leftbtn"></a>
        <a href="javascript:;" class="rightbtn" id="rightbtn"></a>
    </div>
    <script>
        // 得到按钮和ul,ul整体进行运动
        var leftbtn = document.getElementById('leftbtn');
        var rightbtn = document.getElementById('rightbtn');
        var list = document.getElementById('list');

        // 克隆第一张图片
        var cloneli = list.firstElementChild.cloneNode(true);
        list.appendChild(cloneli);

        // 当前ul显示到第几张了,从0开始数
        var idx = 0;

        // 节流锁
        var lock = true;

        // 右边按钮监听
        rightbtn.onclick = function () {
            // 判断锁的状态
            if (!lock) return; 

            lock = false;

            // 给list加过渡,为什么要加??css中不是已经加了么??这是因为最后一张图片会把过渡去掉
            list.style.transition = 'left .5s ease 0s';
            idx ++;
            if (idx > 4) {
                // 设置一个延时器,延时器的功能就是将ul瞬间拉回0的位置,延时器的目的就是让过渡动画结束之后
                setTimeout(function() {
                    // 取消掉过渡,因为要的是瞬间移动,不是“咕噜”回去
                    list.style.transition = 'none';
                    list.style.left = 0;
                    idx = 0;
                }, 500);
            }
            list.style.left = -idx * 650 + 'px';

            // 函数节流
            setTimeout(function() {
                lock = true; 
            }, 500);
        }

        // 左边按钮监听
        leftbtn.onclick = function () {
            if (!lock) return;

            lock = false;

            // 判断是不是第0张,如果是,就要瞬间用假的替换真的
            if (idx == 0) {
                // 取消掉过渡,因为要的是瞬间移动,不是“咕噜”过去
                list.style.transition = 'none';
                // 直接瞬间移动到最后的假图片上
                list.style.left = -5 * 650 + 'px';
                // 设置一个延时器,这个延时器的延时时间可以是0毫秒,虽然是0毫秒,但是可以让我们过渡先是瞬间取消,然后再加上
                setTimeout(function() {
                    // 加过渡
                    list.style.transition = 'left .5s ease 0s';
                    // idx改为真正的最后一张
                    idx = 4;
                    list.style.left = -idx * 650 + 'px';
                }, 0);
            } else {
                idx --;
                list.style.left = -idx * 650 + 'px';
            }
            
            // 函数节流
            setTimeout(function() {
                lock = true; 
            }, 500);
        }
    </script>
</body>
</html>

7.动画效果开发3 - 呼吸轮播图特效

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .carousel {
            width: 650px;
            height: 360px;
            border: 1px solid #000;
            margin: 50px auto;
            position: relative;

        }

        .carousel ul {
            list-style: none;
        }

        .carousel ul li {
            position: absolute;
            top: 0;
            left: 0;
            /* 透明度都是0 */
            opacity: 0;
            transition: opacity 1s ease 0s;
        }

        /* 只有第一张透明度是1 */
        .carousel ul li:first-child {
            opacity: 1;
        }

        .carousel .leftbtn {
            position: absolute;
            left: 20px;
            top: 50%;
            margin-top: -25px;
            width: 50px;
            height: 50px;
            background-color: rgb(28, 180, 226);
            border-radius: 50%;
        }

        .carousel .rightbtn {
            position: absolute;
            right: 20px;
            top: 50%;
            margin-top: -25px;
            width: 50px;
            height: 50px;
            background-color: rgb(28, 180, 226);
            border-radius: 50%;
        }
    </style>
</head>

<body>
    <div class="carousel">
        <ul id="list">
            <li><img src="images/beijing/0.jpg" alt=""></li>
            <li><img src="images/beijing/1.jpg" alt=""></li>
            <li><img src="images/beijing/2.jpg" alt=""></li>
            <li><img src="images/beijing/3.jpg" alt=""></li>
            <li><img src="images/beijing/4.jpg" alt=""></li>
        </ul>
        <a href="javascript:;" class="leftbtn" id="leftbtn"></a>
        <a href="javascript:;" class="rightbtn" id="rightbtn"></a>
    </div>
    <script>
        // 得到按钮和ul,ul整体进行运动
        var leftbtn = document.getElementById('leftbtn');
        var rightbtn = document.getElementById('rightbtn');
        var list = document.getElementById('list');
        var lis = list.getElementsByTagName('li');

        // 当前是第几张图显示
        var idx = 0;

        // 节流
        var lock = true;

        // 右按钮
        rightbtn.onclick = function () {
            // 判断节流
            if (!lock) return;

            lock = false;

            // 还没有改idx,此时的idx这个图片就是老图,老图淡出
            lis[idx].style.opacity = 0;
            idx++;
            if (idx > 4) idx = 0;
            // 改了idx,此时的idx这个图片就是新图,新图淡入
            lis[idx].style.opacity = 1;

            // 动画结束之后,开锁
            setTimeout(function () {
                lock = true;
            }, 1000);
        }

        // 左按钮
        leftbtn.onclick = function () {
            // 判断节流
            if (!lock) return;

            lock = false;

            // 还没有改idx,此时的idx这个图片就是老图,老图淡出
            lis[idx].style.opacity = 0;
            idx--;
            if (idx < 0) idx = 4;
            // 改了idx,此时的idx这个图片就是新图,新图淡入
            lis[idx].style.opacity = 1;

            // 动画结束之后,开锁
            setTimeout(function () {
                lock = true;
            }, 1000);
        }
    </script>
</body>

</html>

二、BOM

BOM(Browser Object Model)指的是浏览器对象模型,它是一个用于描述浏览器窗口和页面文档的JavaScript对象集合。BOM主要提供了与浏览器窗口进行交互的方法和接口,使得开发者可以通过JavaScript来控制浏览器窗口的行为,例如移动、调整大小、弹出新的窗口等。

BOM的一些主要对象包括:

  1. window:代表浏览器窗口,同时也是全局对象,是BOM的核心对象。
  2. document:代表整个HTML文档,虽然通常被认为是DOM(文档对象模型)的一部分,但它也是BOM的一部分,因为它是window对象的属性。
  3. navigator:包含有关浏览器的信息,如名称、版本和系统信息。
  4. screen:提供有关用户屏幕分辨率、可用颜色数等信息。
  5. history:表示浏览器历史记录,可以通过它来前进或后退页面。
  6. location:包含当前URL的信息,并允许你导航到新的页面或修改当前页面的URL。

以下是一些BOM对象的简单示例:

// 使用 window 对象
window.alert("Hello, world!"); // 弹出警告框

// 使用 navigator 对象
console.log(navigator.userAgent); // 输出浏览器的用户代理字符串

// 使用 screen 对象
console.log(screen.width + "x" + screen.height); // 输出屏幕分辨率

// 使用 history 对象
history.back(); // 回退到上一个页面
history.forward(); // 前进到下一个页面

// 使用 location 对象
console.log(location.href); // 输出当前页面的URL
location.href = "https://www.example.com"; // 跳转到新的URL

需要注意的是,BOM没有统一的标准,因此不同浏览器的实现可能会有所不同。随着HTML5的推出,一些BOM的功能被标准化了,例如window对象和location对象的部分功能。

 

1.Windows对象

(1)全局变量是windows变量的属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        var a = 3;
        console.log(window.hasOwnProperty('a')); // true
        console.log(window.a);  // 3
    </script>

    <script src="js/js1.js"></script>
    <script src="js/js2.js"></script>
</body>
</html>

(2)内置函数普遍是window的方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        console.log(window.hasOwnProperty('setInterval'));      // true

        window.setInterval(function () {
            window.console.log('你好');
        }, 1000);
    </script>
</body>

</html>

 

(3)窗口尺寸相关属性

(4)resize事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 监听窗口改变尺寸事件
        window.onresize = function () {
            var root = document.documentElement;
            console.log('窗口改变尺寸了', root.clientWidth, root.clientHeight);
        };
    </script>
</body>
</html>

(5)已动高度

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 5000px;
        }
    </style>
</head>
<body>
    <script>
        // 这两个值是相同的
        console.log(window.scrollY);
        console.log(document.documentElement.scrollTop);
    </script>
</body>
</html>

(6)scroll事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 5000px;
        }
    </style>
</head>
<body>
    <script>
        window.onscroll = function () {
            console.log('窗口卷动了', window.scrollY);
        };
    </script>
</body>
</html>

2.Navigator对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        console.log('浏览器品牌', navigator.appName);
        console.log('浏览器版本', navigator.appVersion);
        console.log('用户代理', navigator.userAgent);
        console.log('操作系统', navigator.platform);
    </script>
</body>
</html>

 

3.History对象

temp.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>我是temp网页</h1>
    <a href="history方法.html">去看history方法页面</a>
</body>
</html>

history.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>我是history方法网页</h1>
    <button id="btn">回退</button>
    <a href="javascript:history.back();">回退</a>
    
    <script>
        var btn = document.getElementById('btn');

        btn.onclick = function() {
            // history.back();//同一个意思
            history.go(-1);
        };
    </script>
</body>
</html>

 

4.Location对象

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn1">点我去看慕课</button>
    <button id="btn2">刷新</button>
    <script>
        var btn1 = document.getElementById('btn1');
        var btn2 = document.getElementById('btn2');

        btn1.onclick = function () {
            window.location = 'http://www.imooc.com';
        };

        btn2.onclick = function () {
            window.location.reload(true);
        };
    </script>
</body>
</html>

 

5.BOM特效开发-01

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            height: 5000px;
            background-image: linear-gradient(to bottom, blue, green, yellow);
        }

        .backtotop {
            width: 60px;
            height: 60px;
            background-color: rgba(255, 255, 255, .6);
            position: fixed;
            bottom: 100px;
            right: 100px;
            /* 小手状 */
            cursor: pointer;
        }
    </style>
</head>

<body>
    <div class="backtotop" id="backtotopBtn">返回顶部</div>

    <script>
        var backtotopBtn = document.getElementById('backtotopBtn');

        var timer;
        backtotopBtn.onclick = function () {
            // 设表先关
            clearInterval(timer);

            // 设置定时器
            timer = setInterval(function () {
                // 不断让scrollTop减少
                document.documentElement.scrollTop -= 200;
                // 定时器肯定要停
                if (document.documentElement.scrollTop <= 0) {
                    clearInterval(timer);
                }
            }, 20);
        };
    </script>
</body>

</html>

 

 

6.BOM特效开发-02

主要会用到事件委托。data-n是自定义属性。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .content-part {
            width: 1000px;
            margin: 0px auto;
            margin-bottom: 30px;
            background-color: #ccc;
            font-size: 50px;
        }

        .floornav {
            position: fixed;
            right: 40px;
            top: 50%;
            margin-top: -100px;
            width: 120px;
            height: 200px;
            background-color: orange;
        }

        .floornav ul {
            list-style: none;
        }

        .floornav ul li {
            width: 120px;
            height: 40px;
            line-height: 40px;
            text-align: center;
            font-size: 26px;
            /* 小手指针 */
            cursor: pointer;
        }

        .floornav ul li.current {
            background: purple;
            color: white;
        }
    </style>
</head>

<body>
    <nav class="floornav">
        <ul id="list">
            <li data-n="科技" class="current">科技</li>
            <li data-n="体育">体育</li>
            <li data-n="新闻">新闻</li>
            <li data-n="娱乐">娱乐</li>
            <li data-n="视频">视频</li>
        </ul>
    </nav>

    <section class="content-part" style="height:674px;" data-n="科技">
        科技栏目
    </section>

    <section class="content-part" style="height:567px;" data-n="体育">
        体育栏目
    </section>

    <section class="content-part" style="height:739px;" data-n="新闻">
        新闻栏目
    </section>

    <section class="content-part" style="height:574px;" data-n="娱乐">
        娱乐栏目
    </section>

    <section class="content-part" style="height:1294px;" data-n="视频">
        视频栏目
    </section>

    <script>
        // 使用事件委托给li添加监听
        var list = document.getElementById('list');
        var contentParts = document.querySelectorAll('.content-part');
        var lis = document.querySelectorAll('#list li');

        list.onclick = function (e) {
            if (e.target.tagName.toLowerCase() == 'li') {
                // getAttribute表示得到标签身上的某个属性值
                var n = e.target.getAttribute('data-n');

                // 可以用属性选择器(就是方括号选择器)来寻找带有相同data-n的content-part
                var contentPart = document.querySelector('.content-part[data-n=' + n + ']');

                // 让页面的卷动自动成为这个盒子的offsetTop值
                document.documentElement.scrollTop = contentPart.offsetTop;
            }
        }


        // 在页面加载好之后,将所有的content-part盒子的offsetTop值推入数组
        var offsetTopArr = [];
        
        // 遍历所有的contentPart,将它们的净位置推入数组
        for (var i = 0; i < contentParts.length; i++) {
            offsetTopArr.push(contentParts[i].offsetTop);
        }
        // 为了最后一项可以方便比较,我们可以推入一个无穷大
        offsetTopArr.push(Infinity);

        console.log(offsetTopArr);

        // 当前所在楼层
        var nowfloor = -1;

        // 窗口的卷动
        window.onscroll = function () {
            // 得到当前的窗口卷动值
            var scrollTop = document.documentElement.scrollTop;

            // 遍历offsetTopArr数组,看看当前的scrollTop值在哪两个楼层之间
            for (var i = 0; i < offsetTopArr.length; i++) {
                if (scrollTop >= offsetTopArr[i] && scrollTop < offsetTopArr[i + 1]) {
                    break;
                }
            }
            // 退出循环的时候,i是几,就表示当前楼层是几
            // 如果当前所在楼层,不是i,表示换楼了
            if (nowfloor != i) {
                console.log(i);
                // 让全局变量改变为这个楼层号
                nowfloor = i;

                // 设置下标为i的项有cur
                for (var j = 0; j < lis.length; j++) {
                    if (j == i) {
                        lis[j].className = 'current';
                    } else {
                        lis[j].className = '';
                    }
                }
            }
        };
    </script>
</body>

</html>

 


http://www.kler.cn/a/378783.html

相关文章:

  • C#属性 Property
  • 使用 Spring Boot 搭建 WebSocket 服务器实现多客户端连接
  • 学webpack之loader原理,让面试官跪下来唱征服
  • Angular数据绑定详解
  • lost+found目录实现文件找回的原理
  • WebStorm技巧
  • Linux常用基本指令和shell
  • RK3568平台开发系列讲解(内存篇)Linux 内存优化
  • wordpress调用指定ID分类内容 并判断第一个与其它输出不同
  • 2025年PMP考试的3A好考吗?
  • YOLO系列再创新高:迎接YOLO11的到来!
  • 再探“构造函数”(2)友元and内部类
  • 机器学习-理论学习
  • 第三十四篇:URL和URI的区别,HTTP系列一
  • 实时监控工作状态!这八款电脑监控软件助你提升效率!
  • Django+Vue全栈开发项目入门(四)
  • 【自动化更新,让商品信息跳舞】——利用API返回值的幽默编程之旅
  • 记录|SQL中日期查询出现的问题
  • 【k8s】-Pod镜像拉取失败问题
  • 为什么 jsp request.getParameter报红,但启动正常?原因在于tomcat内置lib
  • 六、k8s快速入门之容器探针
  • npm入门教程8:缓存管理
  • Swarm-LIO: Decentralized Swarm LiDAR-inertial Odometry论文翻译
  • sed提示不能识别 / 符号
  • 电子电气架构 --- 车载诊断的快速入门
  • 后端java——如何为你的网页设置一个验证码