Skip to content

当我们获取到一个 DOM 元素之后,就可以对 DOM 元素做一些操作,这里介绍我们可以对一个 DOM 元素做哪些操作。

首先,这里先了解一下什么是元素的事件,元素的事件说白了就是某个元素发生了一件事,比如点击了这个 DOM 元素,甚至包括敲击键盘,这些都是事件。由于事件的种类非常多,所以会在后面单独再详细学习,这里只了解一个事件,就是点击事件,也就是这个元素被点击 (click) 的事件。我们学习事件,说白了就是让事件发生之后干一些事,比如被点击之后跳转一个网页,被点击之后输出一段文字,对吧,那这种事件发生之后执行的程序,我们称为事件处理程序。比如这个 DOM 元素,被点击之后,应该输出一段文字,那么就应该给这个 DOM 元素添加一个点击事件,让这个点击事件发生的时候执行一个函数,这个函数的功能就是输出一段文字,这其实就是 DOM 事件的原理。

简而言之,DOM 事件的原理就是,给这个 DOM 添加一个事件,比如鼠标点击事件,当这个事件发生的时候,也就是被点击的时候,执行一段函数。此时我们应该把这个 DOM 对象的点击事件和这个函数绑定起来,说专业一点就是和事件处理程序绑定起来。这个过程叫做事件对象。

所以如果我们用专业一点的术语,我们只要给 DOM 对象注册一个点击事件,就是将一个函数绑定到 DOM 对象的点击事件上去,绑定之后,当 DOM 对象触发了这个点击事件,也就是被点击的时候,就会自动执行这个函数。

html
<!DOCTYPE html>
<html lang="cmn-hans">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    </style>
</head>
<body>
    <button id="btn">点我</button>
    <script>
        var btn = document.getElementById('btn');//获取到DOM元素
        btn.onclick = function () {//给DOM对象绑定事件
            console.log("你点了我");
        }
    </script>
</body>
</html>

由上面的例子可知,要给 DOM 元素绑定一个点击事件,只需要给这个 DOM 元素的 onclick 属性赋值为一个函数即可,此时当点击这个按钮的时候,就会执行该函数,这个函数就是事件处理程序。实际上,DOM 元素上有非常多用于注册事件的属性,这些属性都以 on 开头,如下所示,目前只介绍点击事件

![Pasted image 20240409101124](/notes-assets/02.JavaScript/6.DOM核心/assets/Pasted image 20240409101124.png)

接下来就是正题了,一个元素可以添加属性对吧,比如 img 元素就有 src 属性,alt 属性对吧,我们拿到一个 DOM 元素之后,可以读取和修改这个 DOM 元素的属性。DOM 元素的属性大致可以分为两类,一类是可识别属性,一类是自定义属性,这里简要介绍一下。

  • 可识别属性:即正常的 HTML 属性,也就是有实际意义的属性,例如 input 元素的 value,例如 img 元素的 src。
  • 自定义属性:没有实际意义的属性,例如 value 属性在 input 元素上就有意义,但是在 div 元素上就毫无意义,又例如我就给 div 元素加一个名字叫 a 的属性,这个是我自己取的属性名,没有实际意义。自定义属性主要用来在 DOM 元素上保存一些信息。

对于可识别属性,要获取一个属性的属性值,可以直接使用 DOM元素.属性名 即可,例如下面的例子,再点击按钮的时候,输出文本框的内容,也就是 input 元素的 value 属性值

html
<!DOCTYPE html>
<html lang="cmn-hans">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    </style>
</head>
<body>
    <input id="input" type="text">
    <button id="btn" a="b">点我</button>
    <script>
        var btn = document.getElementById('btn'); // 获取id为btn的按钮元素
        var input = document.getElementById('input'); // 获取id为input的输入框元素
        // 给按钮绑定点击事件
        btn.onclick = function () {
            // 在控制台输出输入框的值
            console.log(input.value);
        }
    </script>
</body>
</html>

此时当点击 btn 的时候,就可以获取到 input 的 value 属性,也就相当于获取到文本框的值。从这里我们可以看到,对于可识别的属性,它直接就是 DOM 元素的属性,这个属性即可读又可写,也就是说我们完全可以给这个属性赋值,从而修改 DOM 元素的属性值。但是对于自定义属性,是不会绑定在 DOM 元素属性上的,我们也没有办法通过 DOM元素.属性名 来获取,如下所示:

html
    <button id="btn" a="b">点我</button>
    <script>
        var btn = document.getElementById('btn'); // 获取id为btn的按钮元素
        // 给按钮绑定点击事件
        btn.onclick = function () {
            console.log(btn.a);//无法获取到属性a,所以输出永远是undefined
        }
    </script>

如果属性是布尔属性,那么得到的属性值为布尔值
有的属性名本身和关键字冲突,例如 label 元素的 for 属性,由于 for 是一个关键字,所以无法直接通过 label.for 获取,于是浏览器给你简答修改了一下,将属性名修改为了 htmlFor。同样,class 也是一个关键字,如果要获取 class 属性,需要使用 className。

这里我们来一个实际的例子,当点击的时候,我要实现点击按钮随机切换图片的效果,随机图片使用 Lorem Picsum 生成

html
<!DOCTYPE html>
<html lang="cmn-hans">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    </style>
</head>
<body>
    <img id="img" src="https://picsum.photos/200/200" alt="">
    <button id="btn" a="b">点我</button>
    <script>
        var btn = document.getElementById('btn'); // 获取id为btn的按钮元素
        var img = document.getElementById('img'); // 获取id为img的输入框元素
        // 给按钮绑定点击事件
        btn.onclick = function () {
            img.src = "https://picsum.photos/200/200?random=" + Math.floor(Math.random() * 100);
        }
    </script>
</body>
</html>

recording

JS 可以修改属性,从而切换图片,有了这个知识,读者应该去尝试一下自行实现一个轮播图效果。

我们考虑一个问题,为什么可识别属性可以通过这种方式来获取,但是自定义属性不行呢?原因很简单,因为可识别属性本身就在 DOM 元素上,例如 input 元素的 DOM 元素,这个 DOM 元素上本身就有 value 这个属性,所以我们可以通过这种方式直接获取属性值,哪怕我们的 input 元素没有写 value 属性,我们也可以获取到一个空字符串,而不是 undefined。但自定义属性这个东西,DOM 元素上就根本没有,哪怕我们在 HTML 元素上加上了这个属性,DOM 元素也不会将这些自定义属性加在

那我前面提到过,有时候我们需要在 HTML 元素上设置一些自定义属性,用于在这个 HTML 元素上保存一些数据,那我现在就要得到这些自定义属性怎么办呢?很简单,DOM 元素上有两个方法,分别是 setAttribute() 和 getAttribute(),分别可以设置和得到属性,第一个参数为属性名,第二个参数为属性值。这种方式不管是自定义属性还是可识别属性都可以正常使用。

html
    <button id="btn" a="b">点我</button>
    <script>
        var btn = document.getElementById('btn'); 
       	console.log(btn.getAttribute("a"));//可以输出b
       	btn.setAttribute("a","c");
        console.log(btn.getAttribute("a"));//可以输出c
    </script>

注意,这种方式虽然可以用于获取和设置属性,但对于一些元素,并不具备交互效果,例如使用这种方式给文本框设置 value 属性后,虽然文本框的 value 属性会发生改变,但是不会在浏览器中显示出来,所以这种方式一般只用来设置自定义属性,对于可识别属性,推荐使用上面的那种直接获取的方式。如果我们要删除自定义属性,使用元素节点上的 removeAttribute(属性名) 方法即可。

关于自定义属性

HTML 5 建议自定义属性使用 data- 作为前缀,例如 data-a,data-abc 这种,写成这样之后,如果尊重这种规范,HTML 5 提供了 dom对象.dataset.属性名 的方式来获取和修改这些自定义属性,也就是说所有以 data 开头的属性都会被维护在一个对象中,我们对自定义属性的管理就可以变成对这个对象的管理,非常方便。
注意,由于 HTML 不区分大小写,所以自定义属性应该使用横杠来分割多个单词,例如我需要添加一个属性为 first name,自定义属性名应该为 data-first-name,此时在 DOM 对象的 dataset 对象中,属性名会被自动转变为 firstName,即自动转换为小驼峰命名法。

上面介绍了如何获取和设置元素的属性,下面就是获取和设置元素的内容,这个很简单,涉及到三个属性

  • dom.innerHTML:获取和设置元素内部的 HTML 文本,也就是源代码。
  • dom.innerText:获取和设置元素内部的纯文本,可以认为是显示出来的文本。
  • dom.textContent:获取和设置元素内部的纯文本,和 innerText 不同的是,这个属性得到是所有文本,而 innerText 得到的仅仅是内容文本。

和 innerHTML 对应的是 outerHTML,innerHTML 可以获取元素内部的 HTML 文本,而 outerHTML 获取到的文本会包含元素本身,同时也可以为其赋值。

html
<div id="test">
        <p>测试</p>
    </div>
    <script>
        var div = document.getElementById('test');
        console.log(div.innerHTML);//<p>测试</p>
        console.log(div.innerText);//测试
        div.innerHTML = `<h1>测试</h1>`
    </script>

接下来我有这样一个需求,我想把 HTML 的元素顺序打乱,如下所示:

html
<ul id="ul1">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <ul id="ul2">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>

在这个结构中,我想把 ul1 中的选项 2 拿出来插入到 ul2 中的末位,为了实现这个操作,就需要引入插入操作,插入操作使用 Node.appendChild(achild),这个方法的作用是在 Node 节点的最后插入一个 achild 节点。

html
<ul id="ul1">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <ul id="ul2">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <script>
        var ul1 = document.getElementById("ul1");//获取ul1
        var ul2 = document.getElementById("ul2");//获取ul2
        var li = ul1.children[1];//获取ul1下的第2个li
        ul2.appendChild(li);//将li添加到ul2
    </script>

![Pasted image 20240409185814](/notes-assets/02.JavaScript/6.DOM核心/assets/Pasted image 20240409185814.png)

注意,这个 appendChild 函数是用于节点操作的,也就是说哪怕是非元素节点,我们依然可以使用这个方法来追加。

但是 appendChild 其实并没有那么好用,因为这个方法只能传入一个参数,如果我要插入 100 个节点,我就得有 100 个 appendChild 操作,同时,插入的必须是一个节点对象,哪怕要插入一个文本,也需要将这文本转换为节点对象后作为参数传入(创建文本节点可以使用 createTextNode 方法),其实有一个更好用的方法是 append,语法为 Element.append(Node1,Node2,...),其作用为将 Node1,Node2,... 这些元素依次插入到 Element 元素的最后,成为其子元素。

append 函数的参数不仅可以接收节点对象,还可以接收字符串,例如 "test",此时 append 函数将把 "test" 自动转换为一个文本节点进行插入。

html
<ul id="ul1">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <ul id="ul2">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <script>
        var ul1 = document.getElementById("ul1");//获取ul1
        var ul2 = document.getElementById("ul2");//获取ul2
        var li1 = ul1.children[1];//获取ul1下的第2个li
        var li2 = ul1.children[2];//获取到ul1下的第3个li
        ul2.append(li1,li2,"test");//依次添加
    </script>

![Pasted image 20240409190546](/notes-assets/02.JavaScript/6.DOM核心/assets/Pasted image 20240409190546.png)

append 方法是一个比较新的方法,在一些很老的浏览器上可能存在兼容性问题,edge 直到 2018 年才支持这个方法。

上面我提到的方法是将元素插入到另一个元素末尾,但是有时候我希望一个元素插入指定位置,比如将下面的 ul1 中的选项 1 插入到 ul2 中选项 2 和选项 3 中间,要实现这种插入就需要引入到一个新方法:Node.insertBefore(newNode,reference),该方法中的 reference 应该是 Node 的子元素,这个方法可以将 newNode 插入到 Node 中成为 Node 的子元素,并且插入位置应该是 reference 之前。

html
<ul id="ul1">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <ul id="ul2">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <script>
        var ul1 = document.getElementById("ul1");//获取ul1
        var ul2 = document.getElementById("ul2");//获取ul2
        var li1 = ul1.children[0];//获取ul1的选项1
        var li2 = ul2.children[2];//获取ul2的选项3
        ul2.insertBefore(li1, li2);//在ul2的选项3之前插入ul1的选项1
    </script>

![Pasted image 20240409191736](/notes-assets/02.JavaScript/6.DOM核心/assets/Pasted image 20240409191736.png)

注意,原生JS 只提供了 insertBefore 方法,并没有提供 insertAfter 方法,也就是说我们只能把一个元素插入到指定元素之前,并不能插入到指定元素之后,实际上,我们完全可以自己封装出 insertAfter 方法

html
    <ul id="ul1">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <ul id="ul2">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <script>
                /**
         * 将新节点插入到父节点中指定参考节点之后。
         * @param {Element} parentNode - 父节点,新节点将被插入到这个节点中。
         * @param {Element} newNode - 新节点,将被插入到父节点中。
         * @param {Element} referenceNode - 参考节点,新节点将被插入到这个节点之后。
         */
        function insertAfter(parentNode, newNode, referenceNode) {
            parentNode.insertBefore(newNode, referenceNode.nextElementSibling);
        }
        // 获取id为'ul1'和'ul2'的两个<ul>元素
        var ul1 = document.getElementById('ul1');
        var ul2 = document.getElementById('ul2');
        // 获取ul1的第二个子节点(<li>元素)和ul2的第三个子节点(<li>元素)
        var li1 = ul1.children[1];
        var li2 = ul2.children[2];
        // 将ul1的第二个<li>元素插入到ul2的第三个<li>元素之后
        insertAfter(ul2, li1, li2);
    </script>

![Pasted image 20240409193538](/notes-assets/02.JavaScript/6.DOM核心/assets/Pasted image 20240409193538.png)

读者可能会有一些疑问,如果 referenceNode 是 parentNode 的最后一个元素,那么 referenceNode.nextElementSibling 得到的结果就是 null,这样并不会产生问题,因为 insertBefore 的第二个参数是可以传入 null 的,当第二个参数传入 null 的情况下,相当于是 appendChild。

很多时候可能我们还需要用到替换操作,即将一个父元素的一个子元素替换为另一个元素,语法也很简单,即 Node.replaceChild(newChild,oldChild),该方法中 oldChild 必须是 Node 节点的子节点,该方法可以将 Node 节点中的 oldChild 替换为 newChild。

以上操作其实都会更改页面的元素结构,更改元素结构之后,会导致页面大面积的重新渲染,所以性能不佳,读者只需要知道,尽量少用即可,但使用 JS 动态改变元素结构也是不可避免的操作。

我们前面提到的都是如何从页面上获取一个已有的元素,实际上,我们还可以凭空创造一个元素,使用 document.createElement() 即可,例如 document.createElement("p"); 就会创建一个 p 元素,此时这个创建的元素和我们获取到的元素是一模一样的,我们也可以使用 innerHTML 修改内部的文本,一样可以给他添加子元素,一样可以把它插入到页面中去。

html
<ul id="ul">
        <li>选项1</li>
        <li>选项2</li>
        <li>选项3</li>
        <li>选项4</li>
    </ul>
    <script>
        var ul = document.getElementById('ul');
        var li = document.createElement('li');
        li.innerText = "选项5";
        ul.append(li);
    </script>

我们最常用的就是 createElement,也就是创建一个元素,因为我们绝大多数情况下都是对元素节点进行操作,当然,除此之外,我们还可以创建其他类型的节点:

  • document.createElement():创建元素节点,参数为元素名
  • document.createTextNode():创建文本节点,参数为文本内容
  • document.createComment():创建注释节点,参数为注释内容
  • document.createAttribute():创建属性节点,参数为属性名,如果要给属性赋值,直接给该节点下的 nodeValue 属性赋值即可
  • document.createFragment():创建文档片段

这里有必要介绍一下文档片段了,我们先来看下面的例子

html
    <ul id="ul">

    </ul>
    <script>
        var ul = document.getElementById('ul');
        for (var i = 1; i <= 30; i++) {
            var li = document.createElement("li");
            li.innerHTML = `选项${i}`;
            ul.append(li);
        }
    </script>

![Pasted image 20240409202110](/notes-assets/02.JavaScript/6.DOM核心/assets/Pasted image 20240409202110.png)

此时使用循环,向 ul 元素内部加入了 30 个 li,但是按照我们刚才介绍过的知识,这种方式并不好,因为我们执行了 30 次的插入操作,也就改变了 30 次的 DOM 结构,所以浏览器会重新渲染 30 次,这是似乎很浪费效率。我们其实可以先创建好 30 个 li 元素,把它放到一个容器里面,然后创建完毕之后一次性插入到 ul 中,这样整个页面只会重新渲染一次。那这 30 个 li 元素应该如何保存在一个容器里面呢,显然,一个变量只能保存一个 li 元素,但如果用一个数组来保存,我要把数组中的所有元素都插入到页面中,一样需要遍历一个一个插入,所以数组其实也不行。这个时候就要用到这个文档片段了,文档片段就可以看做是一个容器,它就是一个普普通通的容器,他不表现出任何内容。我们每创建一个元素,就插入到这个容器里面,等创建完成之后,再将这个容器直接插入到页面中即可。由于在文档片段中插入我们创建的 DOM 元素,这一整个操作都是在内存中的,都不改变 DOM 结构,所以并不会影响什么性能,只有最后一次将文档片段一整个插入的时候,才会改变 DOM 结构,导致重新渲染,所以这样可以大大提升效率。

html
<ul id="ul">

    </ul>
    <script>
        var ul = document.getElementById('ul');
        var frag = document.createDocumentFragment();//创建文档碎片
        for (var i = 1; i <= 30; i++) {
            var li = document.createElement("li");
            li.innerHTML = `选项${i}`;
            frag.append(li);//每次插入到文档碎片
        }
        ul.append(frag);//创建完成后插入到页面中
    </script>

有时候我们希望克隆出一个一模一样的元素,就需要使用 Node.cloneNode(deep),该方法用于克隆一个一模一样的元素,即返回一个和 Node 一模一样的元素。这个 deep 是一个布尔参数,用于选择是否深度克隆,如果填入 false,那么只克隆节点本身(包括自己的属性节点),并不克隆其子节点,如果传入 true,则会把这个元素以及其所有子节点全部克隆。

最后一个对 DOM 元素本身的操作就是删除了,要删除页面上的一个 DOM 元素,可以使用两种方式,一种是父元素删除他的子元素,另一种是自己把自己删掉。

  • Node.removeChild(childNode):该方法可以删除 Node 元素的 childNode 子元素
  • Node.remove():该方法可以删除掉 Node 元素自身

这两种方法可以将一个 DOM 节点从页面上删除,并返回被删除的这个 DOM 对象。

以下是一些练习:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .container {
            width: 400px;
            margin: 0 auto;
        }

        .container li {
            margin: 20px 0;
        }

        .container button {
            margin-left: 10px;
        }
    </style>
</head>
<body>
    <div class="container">
        <p>
            <button>清空</button>
        </p>
        <ul class="list">
            <li>项目1<button>删除</button></li>
            <li>项目2<button>删除</button></li>
            <li>项目3<button>删除</button></li>
            <li>项目4<button>删除</button></li>
            <li>项目5<button>删除</button></li>
            <li>项目6<button>删除</button></li>
            <li>项目7<button>删除</button></li>
            <li>项目8<button>删除</button></li>
            <li>项目9<button>删除</button></li>
            <li>项目10<button>删除</button></li>
        </ul>
    </div>
    <script>
        // 获取页面中特定的元素
        var clear = document.querySelector(".container p button"); // 获取容器中段落内的按钮
        var list = document.getElementsByClassName("list")[0]; // 获取第一个类名为 "list" 的元素
        var removes = document.querySelectorAll(".container li button"); // 获取容器中所有列表项内的按钮
        // 为每个移除按钮添加点击事件处理程序
        for (var i = 0; i < removes.length; i++) {
            removes[i].onclick = function () {
                this.parentElement.remove(); // 当点击按钮时,移除其父元素(即列表项)
            }
        }
        // 为清除按钮添加点击事件处理程序
        clear.onclick = function () {
            list.innerHTML = ""; // 当点击按钮时,清空列表内容
        }
    </script>
</body>
</html>

该练习需要知道 this 指向的问题,在事件处理函数中,this 指向注册该事件的对象

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        span {
            min-width: 50px;
            display: inline-block;
            text-align: center;
            color: red;
        }
    </style>
</head>

<body>
    <p>
        库存的最小值为0
    </p>
    <div class="btns">
        库存:
        <button>-1000</button>
        <button>-100</button>
        <button>-10</button>
        <button>-1</button>
        <span>0</span>
        <button>+1</button>
        <button>+10</button>
        <button>+100</button>
        <button>+1000</button>
    </div>
    <script>
        /**
         * 初始化页面中的按钮点击事件,实现库存数量的加减操作。
         * 当点击按钮时,会根据按钮的文本值(代表加减的数值)对当前库存数量进行相应调整。
         * 如果操作后库存数量小于0,则会提示库存不足。
         */
        var btns = document.querySelectorAll(".btns button"); // 获取页面上所有类名为btns的元素下的button元素
        var text = document.querySelector(".btns span"); // 获取页面上类名为btns的元素下的第一个span元素,用于显示当前库存数量
        for (var i = 0; i < btns.length; i++) {
            // 为每个按钮绑定点击事件
            btns[i].onclick = function () {
                // 获取当前按钮的文本值,转换为数字
                var add = Number(this.innerText);
                // 获取当前库存数量,转换为数字
                var currentNum = Number(text.innerText);
                // 如果加减操作后的库存数量小于0,则提示库存不足,并终止操作
                if (currentNum + add < 0) {
                    alert("库存不足");
                    return;
                }
                // 更新库存数量的显示
                text.innerText = currentNum + add;
            }
        }
    </script>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .container {
            width: 400px;
            margin: 0 auto;
        }

        p {
            text-align: center;
        }
    </style>
</head>

<body>
    <div class="container">
        <p>不能添加空的文本</p>
        <div class="input">
            <input type="text">
            <button>添加</button>
        </div>
        <ul class="list">
            <li>项目1</li>
            <li>项目2</li>
        </ul>
    </div>
    <script>
        // 获取页面中类名为.list的元素、输入类型为text的input元素以及类名中包含input的button元素
        var list = document.querySelector(".list");
        var input = document.querySelector("input[type=text]");
        var button = document.querySelector(".input button");

        // 给按钮添加点击事件处理函数
        button.onclick = function () {
            // 获取输入框中的值,并去除首尾空格
            var value = input.value.trim();
            // 清空输入框
            input.value = "";
            // 如果输入值为空,则弹窗提示并返回
            if (!value) {
                alert("输入框不能为空");
                return;
            }
            // 创建一个li元素,并将输入的值设置为li的文本内容
            var li = document.createElement("li");
            li.innerText = value;
            // 将新创建的li元素添加到列表中
            list.append(li);
        }
    </script>
</body>

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .banner {
            width: 500px;
            margin: 0 auto;
            text-align: center;
        }

        .banner img {
            width: 100%;
            height: 300px;
            object-fit: contain;
            border: 1px solid;
            display: block;
        }
    </style>
</head>

<body>
    <div class="banner">
        <img src="img/1.jpg" alt="">
        <p>
            <button>上一张</button>
            <button>下一张</button>
        </p>
    </div>
    <script>
        // 初始化当前图片索引
        var currentImg = 1;
        // 获取下一个按钮元素
        var next = document.querySelectorAll(".banner button")[1];
        // 获取上一个按钮元素
        var previous = document.querySelectorAll(".banner button")[0];
        // 获取图片元素
        var img = document.querySelector(".banner img");
        // 点击下一个按钮时的事件处理函数
        next.onclick = function () {
            // 如果当前图片索引超过总数,则重置为1
            if (++currentImg > 5) {
                currentImg = 1;
            }
            // 更新图片源为当前索引对应的图片
            img.src = `img/${currentImg}.jpg`;
        }
        // 点击上一个按钮时的事件处理函数
        previous.onclick = function () {
            // 如果当前图片索引小于1,则重置为总数
            if (--currentImg < 1) {
                currentImg = 5;
            }
            // 更新图片源为当前索引对应的图片
            img.src = `img/${currentImg}.jpg`;
        }
    </script>
</body>
</html>
html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .container {
            overflow: hidden;
            width: 550px;
            margin: 0 auto;
        }

        .container .left {
            float: left;
            margin: 0 30px;
        }

        .container select {
            width: 100%;
            height: 200px;
        }

        .container .mid {
            padding-top: 70px;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="left">
            <h2>成哥的现任女友</h2>
            <select id="sel1" multiple>
                <option value="1">幂幂</option>
                <option value="2">花花</option>
                <option value="3">春春</option>
                <option value="4">盈盈</option>
                <option value="5">红红</option>
            </select>
        </div>
        <div class="left mid">
            <p>
                <button title="右移动选中的">&gt;&gt;</button>
            </p>
            <p>
                <button title="右移动全部">&gt;&gt;|</button>
            </p>
            <p>
                <button title="左移动选中的">&lt;&lt;</button>
            </p>
            <p>
                <button title="左移动全部">|&lt;&lt;</button>
            </p>
        </div>
        <div class="left">
            <h2>成哥的前女友</h2>
            <select id="sel2" multiple>
                <option value="6">坤坤</option>
            </select>
        </div>
    </div>
    <script>
        // 获取页面中具有特定title属性的按钮元素和两个目标选框
        var right = document.querySelector('button[title="右移动选中的"]'); // 右移选中项按钮
        var left = document.querySelector('button[title="左移动选中的"]'); // 左移选中项按钮
        var rightAll = document.querySelector('button[title="右移动全部"]'); // 右移全部项按钮
        var leftAll = document.querySelector('button[title="左移动全部"]'); // 左移全部项按钮
        var leftBox = document.getElementById('sel1'); // 左侧选择框
        var rightBox = document.getElementById('sel2'); // 右侧选择框

        // 设置右移按钮点击事件处理函数
        right.onclick = function () {
            // 循环遍历左侧选择框的子元素,将选中的元素移动到右侧选择框
            for (var i = leftBox.children.length - 1; i >= 0; i--) {
                if (leftBox.children[i].selected) {
                    rightBox.appendChild(leftBox.children[i]);
                }
            }
        }
        
        // 设置左移按钮点击事件处理函数
        left.onclick = function () {
            // 循环遍历右侧选择框的子元素,将选中的元素移动到左侧选择框
            for (var i = rightBox.children.length - 1; i >= 0; i--) {
                if (rightBox.children[i].selected) {
                    leftBox.appendChild(rightBox.children[i]);
                }
            }
        }
        
        // 设置左移全部按钮点击事件处理函数
        leftAll.onclick = function () {
            // 将右侧选择框的所有内容移动到左侧选择框,并清空右侧选择框
            leftBox.innerHTML += rightBox.innerHTML;
            rightBox.innerHTML = "";
        }
        
        // 设置右移全部按钮点击事件处理函数
        rightAll.onclick = function () {
            // 将左侧选择框的所有内容移动到右侧选择框,并清空左侧选择框
            rightBox.innerHTML += leftBox.innerHTML;
            leftBox.innerHTML = "";
        }
    </script>
</body>

</html>

以笔记为镜,可以知得失