DOM篇

93 阅读10分钟

DOM 的基本概念及操作

  • DOM(Document Object Model): 文档对象模型

  • 其实就是操作 html 中的标签的一些能力

  • 我们可以操作哪些内容

    • 添加一个div
    • 删除一个li
    • 修改一个ol
    • 获取某一个标签的样式
    • 修改某一个而标签的样式
    • 给某一个标签添加事件
    • 给某一个标签添加属性
    • 给元素添加一些 css 样式
    • ...
  • DOM 的核心对象就是 document 对象。

  • document 对象是浏览器内置的一个对象,内部提供了很多属性和方法,帮我们便捷的操作页面标签。

  • DOM: 页面中的标签, 我们通过 JS 获取到以后, 就把这个对象叫做 DOM 对象。

一、获取标签(元素)

  • 通过 JS 代码来获取页面中的标签, 获取后我们就可以操作这些标签

1、获取非常规元素

  • document.documentElement
  • document.head
  • document.body
    // 1. html
    var htmlEle = document.documentElement
    console.log(htmlEle)
    // 2. head
    var headEle = document.head
    console.log(headEle)
    // 3. body
    var bodyEle = document.body
    console.log(bodyEle)

2、获取常规元素

  • 通过 JS 代码来获取页面中的标签, 获取后我们就可以操作这些标签

1)getElementById

  • getElementById 是通过标签的 ID 名称来获取标签的
  • 因为页面中的 ID 是唯一的, 所以获取到的就是一个元素
    <body>
        <div id="box"></div>
        <script>
            var box = document.getElementById('box')
            console.log(box) // 页面中 ID 为 box 的标签
        </script>
    </body>

2)getElementsByClassName

  • getElementsByClassName 是通过标签的 class 名称来获取标签的
  • 因为页面中可能会有多个元素的 class 名称一样, 所以获取到的是一组元素
  • 哪怕页面中只有一个, 获取到的也是一组元素, 只不过这一组元素只有一个 DOM 元素
    <body>
        <div calss="box"></div>
        <script>
            var box = document.getElementsByClassName('box')
            console.log(box) // [<div></div>]
            console.log(box[0]) // <div></div>
        </script>
    </body>
  • 注意!!! getElementsByClassName 是一组长得很像数组的数据解构, 但它不是数组, 我们叫这种数据结构为: 伪数组
  • 这一组数据也是按照索引排列的, 所以我们想要准确的拿到这个 div, 需要用索引来获取

3)getElementsByTagName

  • getElementsByTagName 是通过标签的 标签名称 来获取标签饿
  • 因为页面中可能有多个元素的标签名称一样, 所以获取到的是一组元素
  • 哪怕只有一个这个标签名, 获取到的也是一组数据, 只不过一组数据中只有一个 DOM 元素
    <body>
        <div></div>
        <script>
            var box = document.getElementsByTagName('div')
            console.log(box) // [<div></div>]
            console.log(box[0]) // <div></div>
        </script>
    </body>
  • 和 getElementsByClassName 一样, 获取到的是一个长得很像数组的元素
  • 必须要用索引才能准确地到 DOM 元素

4)querySelector('像写CSS选择器一样书写标签')

  • querySelector 是按照选择器的方式来获取元素
  • 也就是说, 按照我们写 css 的时候的选择器来获取
  • 这个方法只能获取到一个元素, 并且是页面中第一个满足条件的元素
  • 返回值:符合条件的第一个标签
    // 获取页面中第一个 div 元素
    console.log(document.querySelector('div')) 
    // 获取页面中第一个 有 box 类名的元素
    console.log(document.querySelector('.box')) 
    // 获取页面中第一个 id 名为 box2 的元素
    console.log(document.querySelector('#box2'))  

5)querySelectorAll

  • querySelectorAll 是按照选择器的方式来获取元素

  • 这个方法能获取到所有满足条件的元素

  • 返回值:返回一个符合条件的标签组成的伪数组

    • 伪数组:长得很像数组,也有下标,也有length,但是数组的方法,很多都没有.控制台打印出来数组前面有nodelist
  • 获取不存在的元素,返回值是null

    // 获取页面中的所有的 div 元素
    console.log(document.querySelectAll('div')) 
    // 获取页面中的所有的 类名为 box 的元素
    console.log(document.querySelectAll('.box')) 
  • 获取到的是一组数据, 也是需要用索引来获取到准确的每一个 DOM 元素

二、获取样式

1、style

  • 专门用来个元素添加 css 样式的

1)行内样式

  • 语法:元素/标签.style
  • 能够拿到行内样式,或者给添加一个新的行内样式;
    <div style='width:100px;height:200px;background-color:blue;'></div>

    var div = document.querySelector('div')
    div.style.width = '100px'
    div.style.hright = '100px'
    div.style['background-color] = 'pink'    //能获取,但是有点麻烦
    div.style.backgroundColor = 'pink'       //推荐写法(驼峰命名)

2)内部样式

  • 语法:getComputedStyle('要查询样式的标签').要查询的样式名
  • 非行内样式和行内样式,都能正常获取,但是获取到的值不能修改,只读
    <style>
        .box {
            width: 200px;
            height: 200px;
            background-color: lightblue;
        }
     </style>
     
     <div class="box"></div>
     
     <script>
        var myDiv = document.querySelector('.box')

        //因为元素的样式添加在了类名上,也就是非行内的,所以style获取不到
        console.log(myDiv.style.width)//' '

        //getComputedStyle('要查询样式的标签').要查询的样式名
        console.log(getComputedStyle(myDiv).width)//200px
        console.log(getComputedStyle(myDiv).height)//200px

        //非行内样式和行内样式,都能正常获取,但是获取到的值不能修改
    </script>

三、操作元素类名

1、className

  • 语法:元素/标签.className => 能够得到元素目前拥有的类名
  • 还可以给这个属性重新赋值,然后修改当前标签的类名
    <div class="box1">你好 2310</div>
    <script>
        var box = document.querySelector('.box1')
        console.log(box.className)//box1

        //box.className = 'box2' 当前方式,不管之前有多少类名,全部重新覆盖掉
        box.className += ' box2'//类名之间一定要加 空格
        console.log(box.className)

        //删除类名
        box.className = ''//相当于清空之前的所有类名
    </script>
  • 在设置的时候, 不管之前有没有类名, 都会全部被设置的值覆盖

2、classList

  • 语法:元素/标签.classList
  • 返回值:是一个伪数组,数组内下标对应的是每一个类名,里边的value属性对应的是我们完整类名的字符串
    <div class="box1 abc why">你好 2310</div>
    <script>
        var box = document.querySelector('.box1')
        

        console.log(box.classList)
        //向div这个标签里面追加一个类名box2
        //原本的类名不受影响
        box.classList.add('box2')
        //删除指定类名
        // box.classList.remove('why')
        console.log(box.classList)

    </script>

3、自定义弹框案例

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

    <style>
        * {
            padding: 0;
            margin: 0;
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        .overlay {
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.3);
            position: fixed;
            top: 0;
            left: 0;
        }

        .msg_box {
            width: 280px;
            height: 170px;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: aliceblue;
            border-radius: 10px;
            padding: 20px;
        }

        .msg_box p {
            margin: 24px;
        }

        .close {
            display: none;
        }

        .show {
            display: block;
        }
    </style>
</head>

<body>
    <!-- 点击打开弹出框 -->
    <button id="show_msg_box">展示弹出框</button>

    <!-- 灰色的遮罩层 -->
    <div class="overlay close"></div>

    <!-- 弹出层的信息展示 -->
    <div class="msg_box close">
        <h1>这是一个自定义弹出层</h1>
        <p>广告位招租</p>
        <!-- 点击关闭弹出层 -->
        <button id="close_msg_box">关闭</button>
    </div>

    <script>
        // 0. 获取标签
        var showMsgBox = document.querySelector('#show_msg_box')
        var closeMsgBox = document.querySelector('#close_msg_box')
        var overlay = document.querySelector('.overlay')    // 遮罩层
        var msgBox = document.querySelector('.msg_box')     // 信息框

        // 添加事件

        // 1. 打开弹窗框    遮罩层和弹出框的信息展示
        showMsgBox.onclick = function () {
            // 拿遮罩层举例, 删掉 close 添加类名 show
            overlay.classList.remove('close')
            overlay.classList.add('show')
            // 信息框和上边的遮罩层相同
            msgBox.classList.remove('close')
            msgBox.classList.add('show')
        }

        // 2. 关闭弹出框    遮罩层和弹出框的信息隐藏
        closeMsgBox.onclick = function () {
            // 删掉 show, 添加 close
            overlay.classList.remove('show')
            overlay.classList.add('close')

            msgBox.classList.remove('show')
            msgBox.classList.add('close')
        }
    </script>
</body>

四、操作元素属性

  • 我们获取到元素后, 可以直接操作 DOM的属性, 然后直接把效果展示在页面上
    <div class="box" why1="一个自定义属性" data_name="张三">一个普通的div</div>
    
     var box = document.querySelector('.box')
     console.log(box)

1、获取标签属性

  • 语法:元素.getAttribute('属性名')
    //1、获取标签属性
    console.log(box.getAttribute('class'))//box

    var res = box.getAttribute('why')
    console.log(res)//一个自定义属性

2、设置标签属性

  • 语法:元素.setAttribute('属性名','属性值')
    //2、设置标签属性
    box.setAttribute('whynew2', '内容bee')

3、修改标签属性

  • 语法:元素.setAttribute('属性名','属性值')
    //3、修改标签属性
    box.setAttribute('class', 'whywhy3')

4、H5新增自定义属性

  • H5自定义属性在书写的时候有一个固定的开头就是data-
  • 完整语法:data-属性名 = 属性值
  • 获取的语法:元素/标签.dataset.属性名(属性名不要带data-)
  • 注意点:在设置的时候,不要采用驼峰,全小写,因为就算大写了,浏览器也会转换为小写.
    //4、H5新增自定义属性
    //H5自定义属性在书写的时候有一个固定的开头就是data-
    //完整语法:data-属性名 = 属性值
    //获取的语法:元素/标签.dataset.属性名(属性名不要带data-)
    //注意点:在设置的时候,不要采用驼峰,全小写,因为就算大写了,浏览器也会转换为小写
    console.log(box.dataset.name)//张三
    //新增
    box.dataset.newname = '我是新增的属性'

5、getAttribute

  • 获取元素的某个属性(包括自定义属性)
<div a="100" class="box"></div>

var div = document.querySelector('div')
console.log(div.getAttribute('a'))  // 100
console.log(div.getAttribute('calss'))  // box

6、setAttribute

  • 给元素设置的一个属性(包括自定义属性)
<div></div>

var div = document.querySelector('div')
console.log(div.setAttribute('a', 100))
console.log(div.setAttribute('calss', box))

7、removeAttribute

  • 直接移出元素的某个属性
<div a="100" class="box"></div>

var div = document.querySelector('div')
console.log(div.removeAttribute('calss'))

8、密码框案例

    <input type="password">
    <button>点击展示/隐藏密码</button>
    <script>
        // 0. 获取标签
        var inp = document.querySelector('input')
        var btn = document.querySelector('button')

        // 添加事件
        btn.onclick = function () {
            // console.log(inp.getAttribute('type'))
            // console.dir(inp.type)

            // if (inp.type === 'password') {
            //     inp.type = 'text'
            // } else {
            //     inp.type = 'password'
            // }

            inp.type = inp.type === 'password' ? 'text' : 'password'
        }




        // btn.onclick = function () {
        //     /**
        //      *  逻辑:
        //      *      如果当前是密码框, 那么更改为 输入框
        //      *      如果当前是输入框, 那么更改为 密码框
        //     */
        //     // inp.setAttribute('type', 'text')
        //     // console.log(inp.getAttribute('type'))

        //     if (inp.getAttribute('type') === 'password') {
        //         inp.setAttribute('type', 'text')
        //     } else {
        //         inp.setAttribute('type', 'password')
        //     }
        // }
    </script>

9、全选案例

    全选: <input type="checkbox" class="all_btn">
    <hr>
    <input type="checkbox" class="item"> 兴趣1
    <input type="checkbox" class="item"> 兴趣2
    <input type="checkbox" class="item"> 兴趣3
    <script>
        // 0. 获取标签
        var allBtn = document.querySelector('.all_btn')
        var items = document.querySelectorAll('.item')

        // 1. 给全选按钮添加点击事件
        allBtn.onclick = function () {
            for (var i = 0; i < items.length; i++) {
                items[i].checked = allBtn.checked
            }
        }


        // 2. 给所有的兴趣爱好添加事件
        // 因为 items 是一个伪数组, 所以不能添加点击事件, 只有页面的元素/标签 才能添加
        // items.onclick = function () {}


        // items[0].onclick = function () { console.log(123) }
        // items[1].onclick = function () { console.log(123) }
        // items[2].onclick = function () { console.log(123) }

        // 因为上述的代码比较复杂, 所以可以使用 一个循环进行优化 (前提是, 这几个函数的事件是一样的, 而我们目前案例中就是相同的事件功能)
        // for (var i = 0; i < items.length; i++) {
        //     items[i].onclick = function () {
        //         console.log(123)
        //     }
        // }



        // console.log(setItemChecked) // 是一个函数体
        // console.log(setItemChecked())   // undefined
        // 拆分代码, 进行代码的优化(可读性)
        for (var i = 0; i < items.length; i++) {
            items[i].onclick = setItemChecked
            // items[i].onclick = setItemChecked()
        }

        function setItemChecked() {
            // console.log('判断内部的所有兴趣有没有被选中, 如果有那么选中 全选')

            // 1. 要知道现在有没有全部选中 所有兴趣
            var num = 0
            for (var k = 0; k < items.length; k++) {
                items[k].checked && num++
            }
            // console.log(num, items.length, num === items.length)

            // 2. 根据上边的结果, 决定是否选中 全选
            allBtn.checked = num === items.length
        }



        // allBtn.onclick = function () {
        //     // console.log(allBtn.checked)
        //     if (allBtn.checked === true) {
        //         // 选中 全选按钮, 勾选所有的兴趣按钮
        //         // items[0].checked = true
        //         // items[1].checked = true
        //         // items[2].checked = true
        //         // 上边的三行代码非常麻烦, 所以可以借助一个 for 循环优化
        //         for (var i = 0; i < items.length; i++) {
        //             items[i].checked = true
        //         }
        //     } else {
        //         // 取消勾选 全选按钮, 那么应该 取消勾选所有的兴趣按钮
        //         for (var i = 0; i < items.length; i++) {
        //             items[i].checked = false
        //         }
        //     }
        // }
    </script>

四、操作文本属性

1、innerHTML

  • 获取元素内部的 HTML 解构
<div>
    <p>
        <span>hello</span>
    </p>
</div>
var div = document.querySelector('div')
console.log(div.innerHTML)    // <p><span>hello</span></p>
  • 设置元素内部的 HTML 解构
<div></div>
var div = document.querySelector('div')
div.innerHTML = '<p><span>hello</span></p>'

2、innerText

  • 获取元素内部的文本(只能获取到文本, 获取不到 html 标签)
<div>
    <p>
        <span>hello</span>
    </p>
</div>
var div = document.querySelector('div')
console.log(div.innerHTML)    // hello
  • 设置元素内部的 HTML 解构
<div></div>
var div = document.querySelector('div')
div.innerHTML = '<p><span>hello</span></p>'
  • 会把 <p><span>hello</span></p> 当作一段文本出现在 div 元素内, 而不会把 p 解析成标签

3、value

  • 专门给输入框添加展示文本
        var msg = document.querySelector('#msg')
        var inp = document.querySelector('#inp')

        // msg.innerText = '你好'
        // msg.innerHTML = '我不好'
        // msg.value = '都不好' //value属性是给input输入框设置展示文本,所以设置无效

        //如果想要给input输入框添加展示文本,需要借助value
        inp.value = '你好 value'
        

4、区别

  • innerHTML/innerText能够给输入框之外的标签添加展示文本
  • value专门给输入框添加展示文本
  • innerHTML认识字符串中的标签,能够将字符串中的标签转换成真正的标签进行渲染;获取文本的时候,能够获取到元素的子集标签以及文本
  • innerText不认识字符串中的标签;获取文本的时候,只能获取到元素的子级文本
  • 推荐使用innerText能够防止用户注入恶意代码