IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 02-DOM -> 正文阅读

[JavaScript知识库]02-DOM

DOM

📜学习目标:
    1、能够说出什么是DOM?
    2、掌握如何获取页面元素?
    3、掌握如何给元素注册事件?
    4、怎样操作DOM元素的属性?
    5、如何操作DOM节点?
    梳理方法:元素的创建、增、删、改、查、属性操作、事件操作。

一、Dom简介

  • 定义:文档对象模型(Document Object Model),是处理可扩展标记语言的标准编程接口

  • Dom的作用:a. 可以找到页面中的元素;b. 删除和新建元素;c. 可以对元素的属性和样式进行增删改查

  • Dom树:

    a. 文档:一个页面即一个文档(document);

    b. 元素:页面中所有的标签都是元素(element);

    c. 节点网页中所有的内容都是节点,包括标签、属性、文本、注释等(node)。

    注意:DOM将以上所有内容都看作是对象。

  • 通过DOM获取的元素是一个对象。

二、元素的获取

2.1 通过ID来获取元素

  • 🚩语法表达式:let 存放获得元素的变量名 = document.getElementById(‘需要获取元素的id名’);

    注意:a. 文档加载是从上向下加载的,所以script标签必须写在下面;

    ? b. id 是大小写敏感字符串

    ? c. 如果页面上没有这个id,那通过id获取到的就是null;

    ? d. 返回的是一个元素对象

    ? e. id是唯一的,所以有些浏览器支持:不获取元素,直接用id来代替这个元素。(不推荐这样去做)

    eg:通过ID来获取元素
    <body>
      <div class="one" id="box"></div>
      <script>
          let box1 = document.getElementById('box');
          console.log(box1);
          console.log(box1.id);  //'box'
      </script>
    </body>
    
  • console.dir可以打印返回的元素对象,更好的查看属性和方法

2.2 通过标签名来获取元素们

  • 🚩语法表达式:let 存放获得元素的变量名 = document.getElementsByTagName(‘需要获取元素的标签’);

    注意:a. 返回的是带有指定标签名的对象的集合(伪数组),其中元素对象是动态的

    ? b. 可以采用遍历的方式来依次打印里面的元素

    ? c. 如果标签只有一个,那也是获取到一个伪数组,只不过这个伪数组里面只有一个标签而已

    ? d. 如果页面中没有这个元素返回的是空的伪数组形式

    eg:通过标签名来获取元素们
    <body>
        <ul>
            <li>我是第1个li标签</li>
            <li>我是第2个li标签</li>
            <li>我是第3个li标签</li>
        </ul>
        <script>
        let lis = document.getElementsByTagName('li');
        console.log(lis);//得到所有的li标签
        console.log(lis[2]);//获取到第三个标签
        </script>
    </body>
    
  • 利用这种方法可以获取某个(父元素)内部所指定标签名的子元素

    注:父元素必须是单个对象(必须指明是哪个元素对象)

    <script>
       //body里面只有一个ol时,得到的是只有一个元素伪数组
       let ol = document.getElementByTagName('ol');//[ol]
       //注意:数组不能作为父元素去获取元素
       let lis = ol[0].getElementByTagName('li');
    </script>
    

2.3 通过类名来获取元素们

  • 🚩语法表达式1:let 存放获得元素的变量名 = document.getElementsByClassName(‘需要获取元素的className’);

    注意:a. 返回的是带有指定类名的对象的集合(伪数组);

    ? b. 如果标签只有一个,那也是获取到一个伪数组,只不过这个伪数组里面只有一个标签而已

    eg:
    <body>
        <div class="one two" id="box1">我是div1</div>
        <br>
        <div class="one" id="box2">我是div2</div>
        <script>
        let eles = document.getElementsByClassName('one');
        console.log(eles);//可以得到以上两个div
        </script>
    </body>    
    
  • 🚩语法表达式2:let 存放获得元素的变量名 = document.querySelector(‘选择器’);

  • 🚩语法表达式3:let 存放获得元素的变量名 = document.querySelectorAll(‘选择器’);

    注意:①、document.querySelector获取选择器获取到的元素们的第一个元素

    ? ②、document.querySelectorAll获取选择器获取到的符合选择器的所有元素对象的集合

    ? ③、切记写在括号里面的选择器要加上符号eg:.box、#nav。

    <body>
        <div id="screen">
            <ul id='ul1'>
                <li><a href="#"><img src="./images/09.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/11.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/28.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/39.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/13.jpg" alt=""></a></li>
            </ul>
        </div>
        <script>
           let ul1 = document.querySelector('#ul1'); //获取ul
           let ulLis = document.querySelectorAll('#ul1>li');//获取ul中所有的li标签       
        </script>
    </body> 
    

2.4 获取body和html元素

2.4.1 获取body元素

  • 🚩语法表达式:let 存放获得元素的变量名 = document.body;

    eg:获取body元素
    <script>
        let bodyEle = document.body;
        console.log(bodyEle);
        console.dir(bodyEle);
    </script>
    

2.4.2 获取html元素

  • 🚩语法表达式:let 存放获得元素的变量名 = document.documentElement;

    eg:获取html元素
    <script>
        let htmlEle = document.documentElement;
        console.log(htmlEle);
    </script>
    

2.5 通过name属性来获取元素

  • 🚩语法表达式:let 存放获得元素的变量名 = document.getElementsByName(‘需要获取元素的name属性值’);

    注意:a. 普通标签可以自己定义一个name属性,但是表单元素有默认的name属性

    ? b. 通过name属性获取元素,获取到的是一个伪数组

    let eles = document.getElementsByName('one');
    console.log(eles);
    

三、事件注册和事件触发

3.1 事件基础

  • 事件三要素:

    1、事件源: 事件被触发的对象【谁? 按钮…】
    2、事件类型: 如何触发,什么样的事件【鼠标单击,鼠标双击,鼠标移入…】
    3、事件处理程序: 通过一个函数赋值完成【做什么? 产生什么样的结果?】

    注意:事件的2个时机:1个是注册事件时机,1个触发事件时机

3.2 执行事件的步骤

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 添加事件处理程序(采用函数赋值形式)

3.3 常见的鼠标事件

鼠标事件触发事件
onclick鼠标点击触发
onmouseover鼠标移入触发
onmouseout鼠标移出触发
onfocus获得鼠标焦点触发
onblur失去鼠标焦点触发
onmousemove鼠标移动触发
onmouseup鼠标弹起触发
onmousedown鼠标按下触发

例子见下方4.3案例

四、操作元素

4.1 修改元素内容

  • 以下三种中修改元素内容的方法作用都是:获取/设置双标签文本。

  • 🚩语法表达式1:element.textContent = ‘要修改的内容文本’;

    注意:①、获取从起始位置到终止位置的所有节点(包括子代文本和后代元素的文本),但不能识别html标签,,只会把标签当做文本的一部分,同时会将空格和换行也去掉

    ? ②、设置文本时会覆盖原来的内容,而且如果内容中有标签,不会把标签解析出来

    拓展:textContent才是标准的w3c中用来处理文本的,但是一些老的浏览器比如ie6、7、8不支持)

  • 🚩语法表达式2:element.innerText = ‘要修改的内容文本’;

    注意:①、作用效果与textContent相同,获取从起始位置到终止位置的所有节点(包括子代文本和后代元素的文本),但不能识别html标签,只会把标签当做文本的一部分,同时会将空格和换行也去掉

    ? ②、设置文本时会覆盖原来的内容,而且如果内容中有标签,不会把标签解析出来

    拓展:它是由ie浏览器搞出来的,老的浏览器支持innerText,现在很多新的浏览器也支持,故w3c也将其收录了。

  • 🚩语法表达式3:element.innerHTML = ‘要修改的内容文本’;(使用最多)

    注意:①、获取从起始位置到终止位置的所有节点,可以识别html标签,同时会保留空格和换行

    ? ②、设置文本时会覆盖原来的内容,而且如果内容中有标签,会把标签解析出来

    ? ③、innerHTML只能修改普通盒子里面的内容,不能修改表单里面的value值。

4.2 常用元素的属性操作

  • innerText、innerHTML改变元素内容;
  • src、href
  • id、 alt、title

4.3 表单元素的属性操作

  • 利用DOM可以操作表单的属性:typevalue、checked、selected、disabled

    eg: 表单元素的属性操作
    <body>
        <button>按钮</button>
        <input type = 'text' value = '请输入内容'>
        <script>
            //第一步:获取元素
            let btn = document.querySelector('button');
            let input = document.querySelector('input');
            //第二步:注册事件,处理程序
            btn.onclick = function(){
                //input.innerHTML = '被点击了';innerHTML只能修改普通盒子里面的内容
                //表单里面的值(文字内容)是通过 value 来修改的
                input.value = '被点击了';
                //如果想要使某个表单被禁用/启用,禁用设置disabled为true,启用设置disabled为false;
                this.disabled = true;//使按钮禁用。
                //this 指向的是事件函数的调用者  btn
            }
        </script>
    </body>
    

4.4 样式属性操作

通过 JavaScript修改元素的大小、颜色、位置等样式;

4.4.1 使用 element.style 修改元素样式

  • 🚩语法表达式:element.style.具体样式的属性名 = ‘具体样式的属性值’;(行内样式操作)

  • 使用场景:修改的样式较少,或者功能简单的情况下使用

    注意:a. JS里面的样式采用的是驼峰命名法。eg:fontSize、backgroundColor

    ? b. JS修改 style 样式操作,产生的是行内样式,权重比较高

4.4.2 通过修改元素的className更改元素的样式

  • 🚩语法表达式:element.style.具体样式的属性名 = ‘具体样式的属性值’;(类名样式操作)

  • 使用场景:修改的样式较多,或者功能复杂的情况下使用

  • 使用方法:在css新建一个类选择器,将要修改的样式写入,然后在事件里通过类名调用(this.className = ‘类名’)即可。

    注意:1、👀因为class是一个保留字,因此使用className来操作元素类名属性

    ? 2、className 会直接更改元素的类名,会覆盖原先的类名;

    ? 3、如果想要保留原先的类名,我们可以设置为多类名选择器

  • 相关案例:① 、用户名输入框 显示隐藏内容;②、广告关闭/二维码关闭(直接隐藏即可);③、下拉菜单(鼠标移入即可现实下拉菜单,移出则收回);④、开关灯(一个按钮控制,利用flag=0;假设法来做)。

4.6 排他思想

  • 设计需求:如果有同一组元素,我们想只要其中的某一个实现某种样式,这个时候就需要用到循环的排他思想算法。(????)

  • 设计步骤:a. 所有元素样式全部清除(干掉所有人)

    ? b. 只给当前元素设置样式(留下我自己)

    **注意:**顺序不能颠倒,首先干掉所有人,在给自己设置样式。

    案例引导:
     //当点击按钮中的某一个,则它改变颜色,其他不变。
    <body>
        <button>按钮1</button>
        <button>按钮2</button>
        <button>按钮3</button>
        <button>按钮4</button>
        <button>按钮5</button>
        <script>
            //1、获取所有按钮元素
            let btns = document.getElementByTagName('button');
            //得到的btns是一个伪数组,而我们需要对其中的每一个元素btn[i]设置点击事件,先使用for循环遍历所有元素,再在循环内部统一设置点击事件.
            for(let i = 0; i < btns.length; i++) {
                //2、给每个元素注册事件
                btns[i].onclick = function(){
                    //(1)将所有的按钮背景颜色清除(利用排他思想的第一步:干掉所有人)
                    //此时又要遍历每一个按钮,清除所有按钮背景颜色
                    for(let j = 0; j < btns.length; j++){
                        //将背景颜色设置为空字符串即可
                        btns[j].style.backgroundColor = '';
                    }
                    //(2)给选中的当前元素设置背景颜色(利用排他思想的第二步:留下我自己)
                    this.style.backgroundColor = 'yellowgreen';
                }
            }
    </body>
    
  • 相关案例:①、百度首页换肤案例(美女相册);②、表格隔行换色案例;③、表单全选取消按钮案例(重点掌握

4.7 自定义属性操作

  • 设置自定义属性的目的:为了保存并使用数据,因为有些数据可以只需保存在页面中而不用保存在数据库中。

  • 获取属性值

    ①、element.属性;只能获取内置属性值(即元素本身自带的属性),无法获取自定义属性

    ②、🚩element.getAttribute(‘属性’);通过这种方法可以获取自定义的属性(eg:‘index’)。

  • 设置属性值

    ①、element.属性 = ‘属性值’;对元素的内置属性值进行修改

    ②、🚩element.setAttribute(‘属性’,‘属性值’) ;通过这种方式对自定义的属性值进行修改(eg:‘class’,‘box1’)。

  • 移除属性值:🚩 removeAttribute(‘属性’);

  • (了解)H5自定义属性:以data-开头作为属性名并且赋值(这样做有利于判断是元素的内置属性还是自定义属性)

  • (了解)H5新增获取自定义属性:element.dataset.属性名或者 element.dataset[‘属性名’] 。

    注:H5新增获取自定义属性的缺点:它只能获取以data-开头的自定义属性;兼容性差,ie 11才开始支持。

    eg:自定义属性操作
    <body>
        <div id = 'demo' index = '1' class = 'nav' ></div> 
        <script>
            let div = document.querySelector('div');
            //1、获取元素属性:
            ① console.log(div.id);
            ② console.log(div.getAttribute('index'));
            //2、设置元素属性:
            ① div.id = 'test';
            ② div.setAttribute('index','2')
            //3、移除元素属性:
            div.removeAttribute('index');
        </script>
    </body>
    
    经典案例:tab栏切换(?????)
        <style>
            * {
                margin: 0;
                padding: 0;
            }
    
            ul {
                list-style: none;
            }
    
            .box {
                width: 400px;
                height: 300px;
                border: 1px solid #ccc;
                margin: 100px auto;
            }
    
            .hd {
                height: 45px;
            }
    
            .hd span {
                display: inline-block;
                /*将行内元素转换成行内块元素,宽高才起作用*/
                width: 90px;
                background-color: pink;
                line-height: 45px;
                text-align: center;
                cursor: pointer;
            }
    
            .hd span.current {
                /*交集选择器,标签指定式选择器*/
                background-color: purple;
                /*紫色*/
            }
    
            .bd li {
                height: 255px;
                background-color: purple;
                display: none;
                /*设置隐藏*/
            }
    
            .bd li.current {
                display: block;
                /*显示*/
            }
        </style>
    </head>
    
    <body>
        <div class="box" id="box">
            <div class="hd">
                <span class="current">体育</span>
                <span>娱乐</span>
                <span>新闻</span>
                <span>综合</span>
            </div>
            <div class="bd">
                <ul id="list">
                    <li class="current">我是体育模块</li>
                    <li>我的娱乐模块</li>
                    <li id="li3">我是新闻模块</li>
                    <li>我是综合模块</li>
                </ul>
            </div>
        </div>
    
        <script>
            //需求:1、鼠标点击头部栏会显示不同颜色效果;
            //     2、在头部栏变化的同时下面的商品界面跟着改变
    
            //第一步:实现头部栏切换样式效果
            //1.1 获取元素
            let spanAll = document.querySelectorAll('span');
            let lis = document.querySelectorAll('#list>li');
            //1.2 为每一个span设置点击事件
            // 此处利用到双重for循环。
            // 第一个for循环作用:遍历所有的span,得到一个伪数组,统一为每个span设置点击事件;
            // 第二个for循环作用:利用“排他思想”,先遍历所有的span,将所有span的class属性清除
            for (let i = 0; i < spanAll.length; i++) {
                //设置第二步绑定事件中,所需的索引号
                spanAll[i].setAttribute('index', i);
                //设置点击事件
                spanAll[i].onclick = function () {
                    for (let j = 0; j < spanAll.length; j++) {
                        spanAll[j].setAttribute('class', '');
                    }
                    //“排他思想”第二步:只给自己设置class属性
                    this.setAttribute('class', 'current');
    
                    //第二步:实现下面商品界面的变化
                    // 2.1 设置点击绑定事件
                    //为了使事件绑定,需要自定义索引号,使绑定的事件与点击事件相关联
                    let idx = this.getAttribute('index');
                    //再次使用“排他思想”,将所有的li隐藏(干掉所有人)
                    for (let k = 0; k < lis.length; k++) {
                        lis[k].style.display = 'none';
                    }
                    //“排他思想”第二步:只让被点击相关的绑定事件显示(留下自己)
                    lis[idx].style.display = 'block';
                }
            }
        </script>
    

五、节点操作

5.1 节点

  • 引子:因为通过DOM提供的方法获取元素的方式(第四节中的方法)逻辑性不强,过于繁琐;而节点操作利用父子兄弟节点关系获取元素,这种方法操作简单,逻辑性强,兼容性稍差

  • 节点的三个基本属性值nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)

    nodeNamenodeTypenodeValue
    元素节点元素名1null
    属性节点属性名2属性值
    文本节点#text3文本内容
    注释节点#comment8注释内容
    ducoment#document9null

5.2 节点获取

  • 🚩父节点:element.parentNode;

    注意:得到是离元素最近的父元素,如果找不到父节点那返回的为null

  • 子节点:element.childNodes;

    注意:返回值里面包含了所有的节点,包括元素节点,文本节点和空格等;如果只想要或去里面的元素节点就需要借助 if 判断元素类型是否为 1,所以一般不提倡使用childNodes.

  • 🚩子元素节点:element.children;

    注意:获取到的是所有的子元素节点,实际开发中常用。

  • 兄弟节点:(以下两者都有兼容性问题,可以自己封装一个兼容性函数)

    ①、element.nextSibling / element.previousSibling; 返回当前元素的下一个 / 上一个兄弟节点,找不到返回null,其中包含所有节点;

    ②、🚩element.nextElementSibling / element.previousElementSibling返回当前元素的下一个 / 上一个兄弟元素节点,找不到返回null

  • 第一个子元素节点和最后一个子元素节点:

    ①、element.firstChild / element.lastChild;获取的是第一个/最后一个子节点,可能是文本节点、元素节点及空格等。

    ②、element.firstElementChild / element.lastElementChild;获取的是第一个/最后一个子元素节点(但是这种方法只有ie9才支持)。

    ③、🚩element.children[0] / element.children[element.children.length-1];获取的是第一个/最后一个子元素节点(实际开发中的写法,没有兼容性问题)。

5.3 创建节点

? 需求:当我们想要在页面添加一个新的元素:1、可以创建元素;2、可以添加元素。

5.3.1 创建元素节点

  • 🚩语法表达式:let 节点名 = document.createElement(‘tagName’);

    🚩 追加节点:element.appendChild(节点名);

    注意:①、创建完节点后必须追加节点否则不会显示

? ②、创建节点是在已有元素的后面追加元素,类似于数组中的push方法

5.3.2 插入(添加)元素节点

  • 🚩语法表达式:element.insertBefore(child,指定元素);

    【换一种看待方法:**父元素.insertBefore(元素A,元素B);**把A元素插到B元素前面】

    注意:其中A元素可以是新创建的元素;也可以是已有的元素,可以看作是被剪切后插入B元素前面

    拓展:可以利用element.insertBefore(元素A,元素B.nextElementSibling);来实现将A元素插到B元素的后面。

<body>
    <ul>
        <li>我是第1个li标签</li>
        <li>我是第2个li标签</li>
        <li>我是第3个li标签</li>
    </ul>
    <script>
        //创建元素节点
        let li1 = document.createElement('li');
        //追加节点
        let ul = querySelector('ul');
        ul.appendChild(li1);
        
        //插入节点
        let li2 = document.createElement('li');
        ul.insertBefore(li2,ul.children[0]);//将li2插入到第一个li的前面
     </script>
</body>

5.3.3 三种动态创建元素的区别

  • document.write();是直接将内容写入页面的内容流,如果它在文档流执行完毕后创建元素的话,则会导致页面全面重绘

  • element.innerHTML();是将内容写入某个DOM节点,不会导致页面重绘。创建多个元素时效率更高(采用数组形式拼接),但是结构会稍微复杂

  • document.createElement();创建多个元素效率稍低一些,但是结构更清晰

    注意:不同浏览器下创建多个元素,inner.HTML效率要比createElement高

5.4 删除节点

  • 🚩语法表达式:element.removeChild();从DOM中删除一个子节点,返回删除的节点

5.5 克隆节点

  • 🚩语法表达式:element.cloneNode();方法返回调用该方法的节点的一个副本

    注意:①、如果括号参数为空或者为false,则为浅拷贝,只克隆节点本身,不克隆里面的子节点;

    ? ②、如果括号参数为true,则为深拷贝,会克隆节点本身以及里面所有的子节点

<body>
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>1</li>/*克隆出来的节点*/
    </ul>
    <script>
        let ul = document.querySelector('ul');
        let liNew = ul.children[0].cloneNode(true);//括号里面为false,则会克隆出一个空的li标签
        ul.appendChild(liNew);//克隆后的节点同样需要追加后才会显示出来。
        //简洁方法:ul.appendChild(ul.chilrden[0].cloneNode(true));
    </script>
</body>

六、综合案例:轮播图

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

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

        body {
            background-color: #b6e8f3;
        }

        .banner {
            width: 300px;
            height: 300px;
            background-color: pink;
            margin: 200px auto;
            position: relative;
            overflow: hidden;
        }



        #ul1 {
            position: absolute;
            top: 0;
            left: 0;
            width: 1000%;
            height: 100%;

        }

        #ul1 li {
            float: left;
            width: 10%;
            height: 100%;
            list-style-type: none;
        }

        #ul1 li img {
            width: 100%;
            height: 100%;

        }

        #ol1 {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
        }

        #ol1 li {
            float: left;
            list-style-type: none;
            width: 8px;
            height: 8px;
            border: 1px solid #ccc;
            border-radius: 5px;
            margin-right: 10px;
        }

        #arr {
            display: none;
        }

        #arr #arrLeft {
            position: absolute;
            top: 50%;
            left: 0;
            transform: translateY(-50%);
            width: 20px;
            height: 40px;
            background-color: #000;
            opacity: .5;
            z-index: 8;
        }

        #arrLeft span {
            display: block;
            width: 10px;
            height: 10px;
            border-top: 2px solid #fff;
            border-right: 2px solid #fff;
            margin: auto;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) rotate(-135deg);
        }

        #arr #arrRight {
            position: absolute;
            top: 50%;
            right: 0;
            transform: translateY(-50%);
            width: 20px;
            height: 40px;
            background-color: #000;
            z-index: 8;
            opacity: .5;
        }

        #arrRight span {
            display: block;
            width: 10px;
            height: 10px;
            border-top: 2px solid #fff;
            border-right: 2px solid #fff;
            margin: auto;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) rotate(45deg);
        }

        .current {
            background-color: #fff;
        }
    </style>
</head>

<body>
    <div class="banner" id='box'>
        <div id="screen">
            <!-- 轮播图图片 -->
            <ul id='ul1'>
                <li><a href="#"><img src="./images/01.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/02.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/03.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/04.jpg" alt=""></a></li>
                <li><a href="#"><img src="./images/05.jpg" alt=""></a></li>

            </ul>
            <!-- 轮播图下方的小圆点 -->
            <ol id='ol1'>
                
            </ol>
        </div>
        <!-- 轮播图中的左右按钮 -->
        <div id="arr">
            <a href="javascript:;" id="arrLeft"><span></span></a>
            <a href="javascript:;" id="arrRight"><span></span></a>
        </div>
    </div>
    <script>
        //创建轮播图需求:
        // 1、点击小圆点,显示对应的图片;  
        // 2、点击左右焦点按钮可以实现轮播图的左右切换; 
        // 3、无缝轮播
        // 4、自动轮播

        //思路
        //1.获取相关的元素,获取移动的单位宽. 
        //2.根据轮播图片的个数,创建右下角的小方块们(其实就是li标签),给第一个li标签添加current类(其实就是为了加默认色). 
        //3.简单轮播:①、遍历右下角的小按钮们;②、给每一个小按钮添加索引;③、给每一个小按钮添加点击事件;④、颜色排他:自己的颜色加上(其实就是添加current类);⑤、获取当前点击的整个小方块的索引,计算出目标位置⑥、调用animate方法完成动画.
        //4.大盒子设置鼠标移入移出事件:让左右焦点显示隐藏. 
        //5.左右焦点轮播
        //  右边焦点设置点击事件: ①、移出去图片的个数++;②、计算目标位置;③、调用animate方法完成动画.     
        //  左边焦点设置点击事件:同上。
        //6.实现自动轮播效果:设置一个计时器,鼠标移入时停止自动轮播,鼠标移出重新开始自动播放。

        //1、获取元素
        let box = document.getElementById('box'); //获取大盒子,便于后续做鼠标移入移出事件
        let screen = document.getElementById('screen'); //获取屏幕(即:装轮播图的div)
        let unitWidth = screen.offsetWidth; //因为没有设置padding和border,取得屏幕的宽度即为其offsetWith的大小,并设置为ul移动的单位宽度。
        // console.log(screen.offsetWidth);//打印确认得到的宽度与css属性中设置的宽度所匹配。
        let ul1 = document.querySelector('#ul1'); //获取要做动画的ul标签
        let ulLis = document.querySelectorAll('#ul1>li'); //获取ul中的所有li标签
        let ol1 = document.querySelector('#ol1'); //获取ol
        let arr = document.getElementById('arr'); //获取装左右焦点的大盒子
        let arrLeft = document.getElementById('arrLeft'); //获取左焦点
        let arrRight = document.getElementById('arrRight'); //获取右焦点

        //5.3声明一个变量记录移入移出图片的个数
        let picNum = 0;
        //6.1声明一个计时器
        let timeId = null;

        //2、遍历出ul的li标签的个数,并创建相同个数的li标签,追加到ol中。
        for (let i = 0; i < ulLis.length; i++) {
            //声明一个新的变量,存放自动生成的li
            let liNew = document.createElement('li');
            // liNew.innerHTML = i + 1;//给新建的li标签里设置内容
            //将生成的li标签追加到ol中
            ol1.appendChild(liNew);
        }
        //声明一个变量,获取ol的所有子元素
        let olLis = ol1.children;
        // let lisOl = document.querySelectorAll('#box ol>li');//与上一行代码等同
        olLis[0].setAttribute('class', 'current'); //设置第一个小圆点为默认选中的状态

        //3、简单轮播:step1:遍历ol中的所有li标签;step2:为每一个li设置点击事件;step3:给ol中的li设置索引号;step4:颜色排他;step5:获取索引,计算出目标位置,调用动画,使当点击小圆点则显示对应的图片
        for (let i = 0; i < olLis.length; i++) {
            //给小圆点(ol的li)设置索引号
            olLis[i].setAttribute('index', i);
            //遍历ol中所有的li
            olLis[i].onclick = function () {
                //利用“排他思想”给点击的小圆点(ol的li)设置对应的属性
                //利用for循环遍历所有li,进行颜色属性清除
                for (let j = 0; j < olLis.length; j++) {
                    olLis[j].removeAttribute('class');
                }
                //只给自己(被点击的li)设置颜色属性效果(即单独添加current类)
                this.setAttribute('class', 'current');
                //给获取点击的小圆点(ol的li)的索引,计算出目标位置
                let index = this.getAttribute('index');
                //目标位置:索引号数 x 移动单位的宽度
                let target = -index * unitWidth;
                //调用animate方法完成动画,动画移动的对象是ul
                animate(ul1, target);
            }
        }

        //5.1 克隆ul中的第一个li标签并追加到ul中(其实就是第6张图片,克隆出来的)
        ul1.appendChild(ulLis[0].cloneNode(true));

        //4、给大盒子设置鼠标移入移出事件
        //给大盒子设置鼠标移入事件
        box.onmouseover = function () {
            //鼠标移入时,左右焦点显示
            arr.style.display = 'block';
            // 6.1清空计时器,使鼠标移入时,停止轮播图自动播放
            clearInterval(timeId);
        }
        //给大盒子设置鼠标移入事件
        box.onmouseout = function () {
            //鼠标移出时,左右焦点隐藏
            arr.style.display = 'none';
            // 6.2 鼠标移出时,轮播图继续自动播放
            timeId = setInterval(clickRight, 2000);

        }

        //5、  step1:克隆ul第一个子元素并追加到最后;step2:给左右焦点设置点击事件,使显示的图片与小圆点的索引相对应;step3:声明一个变量记录移入移出图片的个数;step4:实现无缝轮播
        //为右焦点设置点击事件 
        arrRight.onclick = function () {
            //调用右焦点点击事件函数
            clickRight();
        }

        //封装右焦点点击事件函数:因为后续中轮播图的自动轮播,类似于等间隔自动点击右焦点,所以将其封装成一个函数clickRight,减少代码冗余,便于调用
        function clickRight() {
            //判断:如果现在显示克隆那张(即索引号=5),那就使他直接等于第一张(即索引号=0),同时使ul与父盒子左边的距离为0px。
            if (picNum == 5) {
                picNum = 0;
                ul1.style.left = 0 + 'px';
            }
            // 移出去的图片个数++
            picNum++;
            // 计算出目标位置:移出去图片个数 x 移动单位的宽度
            let target = -picNum * unitWidth;
            animate(ul1, target);
            //利用“排他思想”,给点击的图片对应的小方块设置颜色属性
            for (let i = 0; i < olLis.length; i++) {
                olLis[i].removeAttribute('class');
            }
            //一点小细节处理 ,此处利用判断:当移出5张图片,显示的就是克隆的那张的时候,此时令索引号为0的添加选中属性。
            if (picNum == 5) {
                olLis[0].setAttribute('class', 'current');
            } else {
                // 而其他情况下:移出去几张则索引号为几的添加选中属性
                olLis[picNum].setAttribute('class', 'current');
            }
        }
        
        //为左焦点设置点击事件 
        arrLeft.onclick = function () {
            //判断:如果现在是第一张(即索引号=0),那就使他直接等于被克隆的那张(即索引号=5),同时使ul最左端与父盒子左边的距离为从父盒子最左端截至到克隆的位置的个数乘以宽度距离。
            if (picNum == 0) {
                picNum = 5;
                ul1.style.left = -picNum * unitWidth + 'px';
            }
            // 移出去图片的个数--
            picNum--;
            let target = -picNum * unitWidth;
            animate(ul1, target);
            for (let i = 0; i < olLis.length; i++) {
                olLis[i].removeAttribute('class');
            }
            olLis[picNum].setAttribute('class', 'current');
        }

        //6、实现自动轮播效果
        //step1:声明一个计时器;step2:封装右焦点点击事件函数;step3:调用step2中封装好的函数; step4:鼠标移入自动轮播结束,清空计时器;鼠标移出计时器重启。
        timeId = setInterval(clickRight, 2000);

        //创建ul的移动动画,并封装动画
        function animate(ele, target) {
            clearInterval(ele.timeId)
            ele.timeId = setInterval(function () {
                let currentLeft = ele.offsetLeft;
                let step = target > currentLeft ? 9 : -9;
                currentLeft += step;
                if (Math.abs(target - currentLeft) > Math.abs(step)) {
                    ele.style.left = currentLeft + 'px';
                } else {
                    ele.style.left = target + 'px';
                    clearInterval(ele.timeId);
                }
            }, 30)
        }
    </script>
</body>

</html>
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-12 19:30:07  更:2021-11-12 19:30:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 22:04:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码