跳转至

(附加)DOM和BOM小练习

约 523 个字 453 行代码 5 张图片 预计阅读时间 7 分钟

练习1:切换图片(DOM基础练习)

目标:

  1. 上一张按钮:点击后查看上一张图片,如果是第一张图片,则查看最后一张图片
  2. 下一张按钮:点击后查看下一张图片,如果是最后一张图片,则查看第一张图片
  3. 图片顶部文字:显示总共图片个数,已经当前图片的序号

实现效果:

参考代码:

HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>切换图片</title>
    <style>
        .outer {
            width: 640px;
            margin: 50px auto;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="outer">
        <p></p>
        <img src="./images/1.png">
        <button id="prev" type="button">上一张</button>
        <button id="next" type="button">下一张</button>
    </div>
</body>
<script src="test.js"></script>
</html>
JavaScript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 将照片位置加载到数组中
const arr = ["./images/1.png", "./images/2.png", "./images/3.png", "./images/4.png", "./images/5.png"];

// 获取到img中的src属性
let image = document.querySelector("img");
// console.log(image);

// 设置当前下标
let index = 0;

// 获取当前的p标签
let content = image.previousElementSibling;
// console.log(content);
content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;

// 获取到按钮,并绑定事件
let next = document.querySelector("#next");
// console.log(next);
next.addEventListener("click", () => {
    // 点击下一张更新index
    index = (++index) % 5;
    image.src = arr[index];

    content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;
});

let prev = document.querySelector("#prev");
// console.log(prev);
prev.addEventListener("click", () => {
    index = index % 5;
    // 点击上一张更新index
    --index;
    if(index < 0)
    {
        index = arr.length - 1;
    }
    image.src = arr[index];

    content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;
});

练习2:选项框功能实现

目标:

  1. 最上方的选项框:一共实现下面的效果:

    1. 选中该选项框,全选下方所有的爱好选项框
    2. 如果有一个爱好选项框取消选中,则最上方的选项框同时取消选中
    3. 如果单独选中所有爱好选项框,则最上方的选项框同时选中
  2. 爱好选项框下方的按钮:分别对应的功能:

    1. 全选按钮:点击后选中所有爱好选项框
    2. 取消选中按钮:点击后取消选中所有爱好选项框
    3. 反选按钮:点击后根据爱好选项框当前的状态,选中的设置取消选中,未选中的设置选中
    4. 提交按钮:提交已经选中的爱好
  3. 同步下面的按钮和最上方的全选框

实现效果参考:

HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>全选功能实现</title>
</head>
<script defer src="./test.js"></script>
<body>
    <form>
        Please choose your hobby:
        <input class="full_up" type="checkbox"> Full check<br/>
        <input class="ppb" type="checkbox" name="hobby" value="Ping Ping Ball"> Ping Ping Ball
        <input class="bskball" type="checkbox" name="hobby" value="Basketball"> Basketball
        <input class="bmt" type="checkbox" name="hobby" value="Badminton"> Badminton
        <input class="ftb" type="checkbox" name="hobby" value="Football"> Football<br/>
        <button class="full_down" type="button">Full check</button>
        <button class="cc" type="button">Cancel check</button>
        <button class="co" type="button">Check oppsite</button>
        <button class="submit" type="button">submit</button>
    </form>
</body>
</html>
JavaScript
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
// 获取到所有兴趣爱好
let hobbies = document.querySelectorAll("[name='hobby']");
// console.log(hobbies);

// 处理下方全选的按钮
let fullCheckDown = document.getElementsByClassName("full_down")[0];
// console.log(fullCheckDown);
fullCheckDown.addEventListener("click", () => {
    // 将所有的兴趣爱好选择框设置为选中
    for (const hobby of hobbies) {
        hobby.checked = true;
    }

    if(isChecked(hobbies))
        fullCheckUp.checked = true;
});

// 处理下方取消全选按钮
let cancel = document.getElementsByClassName("cc")[0];
// console.log(cancel);
cancel.addEventListener("click", () => {
    // 取消选中所有的兴趣爱好选项框
    for (const hobby of hobbies) {
        hobby.checked = false;
    }

    if(!isChecked(hobbies))
        fullCheckUp.checked = false;
});

// 处理反选按钮
let oppsite = document.getElementsByClassName("co")[0];
// console.log(oppsite);
oppsite.addEventListener("click", () => {
// 遍历找到爱好选项框,如果选中则取消选中,否则选中
    for (const hobby of hobbies) {
        if (!hobby.checked)
            hobby.checked = true;
        else
            hobby.checked = false;
    }

    if(isChecked(hobbies))
        fullCheckUp.checked = true;
    else
        fullCheckUp.checked = false;
});

// 处理提交按钮
let submit = document.getElementsByClassName("submit")[0];
submit.addEventListener("click", () => {
    // 提交已经选择的选项框的
    for (const hobby of hobbies) {
        if (hobby.checked)
            console.log(hobby.value);
    }
});

// 记录未选中的选项框
let count = 0;

// 处理上面的全选按钮
let fullCheckUp = document.getElementsByClassName("full_up")[0];
fullCheckUp.addEventListener("click", () => {
    // 点击全选框时,全选所有爱好
    // 但是还需要考虑两种情况:
    // 1. 如果全选框选中后,用户取消选中了一个爱好,就需要取消选中全选框
    // 2. 如果用户单独选中了所有爱好,则需要一并选中全选框
    if(fullCheckUp.checked)
    {
        for (const hobby of hobbies) {
            hobby.checked = true;
        }
    }
    else
    {
        for (const hobby of hobbies) {
            hobby.checked = false;
        }
    }
});

// 判断是否选中
function isChecked(hobbies) {
    for (const hobby of hobbies) {
        if(!hobby.checked)
            return false;
    }

    return true;
}

// 考虑剩余两种情况
for (const hobby of hobbies) {
    hobby.addEventListener("click", () => {
        // 第一种情况
        if(fullCheckUp.checked) {
            for (const hobby1 of hobbies) {
                if (!hobby1.checked)
                    fullCheckUp.checked = false;
            }
        }

        // 第二种情况
        if(isChecked(hobbies))
            fullCheckUp.checked = true;
    });
}

练习3:添加及删除员工

目标:

  1. 点击删除链接:删除当前行的员工
  2. 点击添加按钮时:根据输入框的内容添加新行,注意,新添加的员工对应的删除功能也需要生效

实现效果参考:

参考代码:

HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>添加以及删除员工</title>
    <style>
        .outer {
            width: 400px;
            margin: 100px auto;
            text-align: center;
        }

        table {
            width: 400px;
            border-collapse: collapse;
            margin-bottom: 20px;
        }

        td,
        th {
            border: 1px black solid;
            padding: 10px 0;
        }

        form div {
            margin: 10px 0;
        }

        a {
            text-decoration: none;
            color: gray;
        }
    </style>
</head>
<body>
    <div class="outer">
        <table>
            <tbody>
            <tr>
                <th>姓名</th>
                <th>邮件</th>
                <th>薪资</th>
                <th>操作</th>
            </tr>
            <tr>
                <td>孙悟空</td>
                <td>swk@hgs.com</td>
                <td>10000</td>
                <td><a href="javascript:;" class="delete">删除</a></td>
            </tr>
            <tr>
                <td>猪八戒</td>
                <td>zbj@glz.com</td>
                <td>8000</td>
                <td><a href="javascript:;" class="delete">删除</a></td>
            </tr>
            <tr>
                <td>沙和尚</td>
                <td>shs@lsh.com</td>
                <td>6000</td>
                <td><a href="javascript:;" class="delete">删除</a></td>
            </tr>
            </tbody>
        </table>

        <form action="#">
            <div>
                <label for="name">姓名</label>
                <input type="text" id="name" />
            </div>
            <div>
                <label for="email">邮件</label>
                <input type="email" id="email" />
            </div>
            <div>
                <label for="salary">薪资</label>
                <input type="number" id="salary" />
            </div>
            <button>添加</button>
        </form>
    </div>
</body>
<script src="./test.js"></script>
</html>
JavaScript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 实现删除功能
// 获取所有删除的链接
let del = document.getElementsByClassName("delete");
// console.log(del);
// for (const delElement of del) {
//     delElement.addEventListener("click", () => {
//         // 删除当前行
//         // 获取到当前删除键所在行
//         let delParent = delElement.parentNode.parentNode;
//         // console.log(delParent);
//         // 调用删除元素节点方法
//         delParent.remove();
//     });
// }

for (const delElement of del) {
    delElement.addEventListener("click", _toDel);
}

function _toDel()
{
    // 删除当前行
    // 获取到当前删除键所在行
    // this代表当前调用的对象
    let delParent = this.parentNode.parentNode;
    // console.log(delParent);
    // 调用删除元素节点方法
    delParent.remove();
}

// 实现添加功能
// 点击添加按钮后插入数据
// 获取表格
let table = document.querySelector("tbody");
let button = document.querySelector("button");
button.addEventListener("click", () => {
    // 获取用户输入到输入框的内容
    // 使用value属性
    let username = document.querySelector("#name").value;
    let email = document.querySelector("#email").value;
    let salary = document.querySelector("#salary").value;
    console.log(username);
    console.log(email);
    console.log(salary);

    // 将用户输入的数据插入到表格中
    let row = document.createElement("tr");
    // 使用依次添加用户输入的内容防止xss注入
    let col1 = document.createElement("td");
    let col2 = document.createElement("td");
    let col3 = document.createElement("td");
    let col4 = document.createElement("td");

    col1.innerText = `${username}`;
    col2.innerText = `${email}`;
    col3.innerText = `${salary}`;

    row.appendChild(col1);
    row.appendChild(col2);
    row.appendChild(col3);

    // 插入删除按钮
    col4.innerHTML = "<a href='javascript:;' class='delete'>delete</a>";
    row.appendChild(col4);

    table.appendChild(row);

    // 将删除功能重新添加给新的内容
    // 为新连接添加属性
    // 动态更新,最后一个连接就是新的连接
    del[del.length - 1].addEventListener("click", _toDel);
});

练习4:自动切换图片(DOM+BOM练习)

本练习是练习1的拓展版本,建议先练习完练习1后再尝试本题

HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <title>切换图片</title>
    <style>
        .outer {
            width: 640px;
            margin: 50px auto;
            text-align: center;
        }
    </style>
</head>
<body>
<div class="outer">
    <p></p>
    <img src="./images/1.png">
    <button id="prev" type="button">上一张</button>
    <!-- 自动切换按钮 -->
    <button id="auto" type="button">自动</button>
    <button id="next" type="button">下一张</button>
</div>
</body>
<script src="test.js"></script>
</html>
JavaScript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 将照片位置加载到数组中
const arr = ["./images/1.png", "./images/2.png", "./images/3.png", "./images/4.png", "./images/5.png"];

// 获取到img中的src属性
let image = document.querySelector("img");
// console.log(image);

// 设置当前下标
let index = 0;

// 定时器
let timer;

// 获取当前的p标签
let content = image.previousElementSibling;
// console.log(content);
content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;

// 获取到按钮,并绑定事件
let next = document.querySelector("#next");
// console.log(next);
next.addEventListener("click", () => {
    // 关闭上一次的定时器
    // clearTimeout(timer);
    clearInterval(timer);
    // 点击下一张更新index
    index = (++index) % 5;
    image.src = arr[index];

    content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;
});

let prev = document.querySelector("#prev");
// console.log(prev);
prev.addEventListener("click", () => {
    // 关闭上一次的定时器
    // clearTimeout(timer);
    clearInterval(timer);
    index = index % 5;
    // 点击上一张更新index
    --index;
    if(index < 0)
    {
        index = arr.length - 1;
    }
    image.src = arr[index];

    content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;
});

// 处理自动按钮
let auto = document.getElementById("auto");
auto.addEventListener("click", () => {
    timer = setInterval(() => {
        index = (++index) % 5;
        image.src = arr[index];

        content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;
    }, 1000);
});

// 上面的方式只能确保是自动切换
// 如果用户手动点击上一张或者下一张则可能因为事件循环导致自动切换和用户操作重叠
// 考虑当用户手动点击上一张或者下一张时关闭当前的定时器,再次点击自动时开启自动切换
// 所以需要在用户点击上一张或者下一张时关闭定时器
// 可以考虑使用setTimerOut()模拟实现setInterval()
// auto.addEventListener("click", () => {
//     timer = setTimeout(function alter() {
//         // 清除上一次的定时器
//         clearTimeout(timer);
//         index = (++index) % 5;
//         image.src = arr[index];
//
//         content.innerText = `There are ${arr.length} pictures, It is No.${index % 5 + 1} picture`;
//
//         // 开启下一次的定时器
//         timer = setTimeout(alter, 1000);
//     }, 1000);
// });

拓展

本案例还可以拓展,例如默认图片就是自动切换的,当用户点击上一张按钮或者下一张按钮时暂定切换,等待一段时间后再重新自动切换