• web 面试高频考点 —— JavaScript-Web-API 篇(一)DOM、BOM、事件


    系列文章目录



    JS-Web-API-DOM

    DOM 节点操作

    获取 DOM 节点

    • document.getElementById():返回对拥有指定 id 的第一个对象的引用。
    • document.getElementsByTagName():返回带有指定标签名的对象集合。
    • document.getElementsByClassName():返回一个包含了所有指定类名的子元素的类数组对象。
    • document.querySelectorAll():返回与指定的选择器组匹配的文档中的元素列表 (使用深度优先的先序遍历文档的节点)。返回的对象是 NodeList 。

    示例:获取 DOM 节点的 Demo

        <div id="div1" class="container">
            <p>一段文字</p>
            <p>一段文字</p>
            <p>一段文字</p>
        </div>
        <div id="div2" class="container">
            <img src="./code.png">
        </div>
        
    	const div1 = document.getElementById('div1')
        console.log('div1', div1)
    
        const divList = document.getElementsByTagName('div')
        console.log('divList.length', divList.length)
        console.log('divList[1]', divList[1])
    
        const containerList = document.getElementsByClassName('container')
        console.log('containerList.length', containerList.length)
        console.log('containerList[1]', containerList[1])
    
        const pList = document.querySelectorAll('p')
        console.log('pList', pList)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    DOM 节点的 property 和 attribute

    • property:修改对象属性,不会体现到 html 结构中
    • attribute:修改 html 属性,会改变 html 结构
    • 两者都有可能引起 DOM 的重新渲染

    示例 1:property 修改对象属性(推荐使用)

    	.container {
            border: 1px solid #ccc;
        }
        .red {
            color: red;
        }
    
        <div id="div1" class="container">
            <p>一段文字1</p>
            <p>一段文字2</p>
            <p>一段文字3</p>
        </div>
    
        // property 形式
        const pList = document.querySelectorAll('p')
        const p1 = pList[0]
    
        p1.style.width = '100px'
        console.log(p1.style.width)
        p1.className = 'red'
        console.log(p1.className)
        console.log(p1.nodeName)
        console.log(p1.nodeType)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    示例 2:attribute 修改 html 属性

    	.container {
            border: 1px solid #ccc;
        }
        .red {
            color: red;
        }
    
        <div id="div1" class="container">
            <p>一段文字1</p>
            <p>一段文字2</p>
            <p>一段文字3</p>
        </div>
        
        // attribute 
        const pList = document.querySelectorAll('p')
        const p1 = pList[0]
        p1.setAttribute('data-name', 'imooc')
        console.log(p1.getAttribute('data-name'))
        p1.setAttribute('style', 'font-size: 30px;')
        console.log(p1.getAttribute('style'))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    在这里插入图片描述

    DOM 结构操作

    新增、插入、移动节点

    • 新增节点:createElement
    • 插入节点:appendChild
    • 移动节点:已有的节点插入到别的容器就会发生移动

    示例:

        <div id="div1" class="container">
            <p id="p1">一段文字1</p>
            <p>一段文字2</p>
            <p>一段文字3</p>
        </div>
        <div id="div2" class="container"></div>
    
        const div1 = document.getElementById('div1')
        const div2 = document.getElementById('div2')
        const newP = document.createElement('p')
        // 新建节点
        newP.innerHTML = '新增的一段文字'
        // 插入节点
        div1.appendChild(newP)
        // 移动节点
        const p1 = document.getElementById('p1')
        div2.appendChild(p1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    获取子元素列表 & 获取父元素

    • parentNode:父元素
    • childNodes:子元素
    • removeChild:删除子元素

    示例 1:div1ChildNodes 不是数组,需要Array.from() 转为数组

        <div id="div1" class="container">
            <p id="p1">一段文字1</p>
            <p>一段文字2</p>
            <p>一段文字3</p>
        </div>
    
    	const div1 = document.getElementById('div1')
    	// 获取父元素
        console.log(p1.parentNode)
    
        // 获取子元素列表
        const div1ChildNodes = div1.childNodes
        console.log(div1.childNodes)
        const divChildNodesP = Array.from(div1ChildNodes).filter(child => {
            if(child.nodeType === 1) {
                return true
            }
            return false
        })
        console.log('divChildNodesP', divChildNodesP)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

    删除子元素

    示例:在上文的基础上进行删除子元素

    	div1.removeChild(divChildNodesP[0])
    
    • 1

    在这里插入图片描述

    如何优化 DOM 操作的性能

    DOM 查询做缓存

    • 做缓存,先接收所有的 length,避免循环的时候重复操作 DOM

    示例 1:

        // 不缓存 DOM 查询结果
        for(let i = 0; i < document.getElementsByTagName('p').length; i++) {
            // 每次循环,都会计算 length,频繁进行 DOM 查询
        }
    
    • 1
    • 2
    • 3
    • 4

    示例 2:

        // 缓存 DOM 查询结果
        const pList = document.getElementsByTagName('p')
        const length = pList.length
        for(let i = 0; i < length; i++) {
            // 缓存 length,只进行一次 DOM 查询
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    将频繁操作改为一次性操作

    • 创建文档片段,把循环的内容先插入到文档片段中

    示例 1:频繁的 DOM 操作

        <ul id="list"></ul>
        
        const list = document.getElementById('list')
        for(let i = 0; i < 10; i++) {
            const li = document.createElement('li')
            li.innerHTML = `List item ${i}`
            list.appendChild(li)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    示例 2:创建文档片段

        <ul id="list"></ul>
        
        const list = document.getElementById('list')
        // 创建一个文档片段,此时还没有插入到 DOM 树中
        const frag = document.createDocumentFragment()
        // 执行插入
        for(let i = 0; i <= 10; i++) {
            const li = document.createElement('li')
            li.innerHTML = `List item ${i}`
            // 先插入文档片段中
            frag.appendChild(li)
        }
        // 都完成之后,再统一插入到 DOM 树中
        list.appendChild(frag)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    JS-Web-API-BOM

    BOM 操作相关面试题

    navigation 和 screen

    • navigation.userAgent:浏览器用于 HTTP 请求的用户代理头的值
    • screen.width:屏幕宽度
    • screen.height:屏幕高度
      在这里插入图片描述

    拆解 url 各部分

    • location.href:返回完整的URL
    • location.protocol:返回一个URL协议
    • location.host:返回一个URL的主机名和端口
    • location.search:返回一个URL的查询部分
    • location.hash:返回一个URL的锚部分
    • location.pathname:返回的URL路径名。
      在这里插入图片描述

    JS-Web-API-事件

    事件绑定

    示例:通用事件绑定函数

    	<button id="btn1">一个按钮</button>
    
    	function bindEvent(elem, type, fn) {
            elem.addEventListener(type, fn) 
        }
    
        const btn1 = document.getElementById('btn1')
        bindEvent(btn1, 'click', event => {
        	console.log(event.target) // 
            alert('clicked')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    事件冒泡

    • 基于 DOM 树形结构
    • 事件会顺着触发元素往上冒泡
    • 应用场景:代理
    • stopPropagation:用于阻止事件冒泡
        <div id="div1">
            <p id="p1">激活</p>
            <p id="p2">取消</p>
            <p id="p3">取消</p>
            <p id="p4">取消</p>
        </div>
        <div id="div2">
            <p id="p5">取消</p>
            <p id="p6">取消</p>
        </div>
    
    	function bindEvent(elem, type, fn) {
            elem.addEventListener(type, fn)
        }
        const p1 = document.getElementById('p1')
        const body = document.body
        bindEvent(p1, 'click', event => {
            event.stopPropagation() // 阻止冒泡
            console.log('激活')
        })
        bindEvent(body, 'click', event => {
            console.log('取消')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    不阻止冒泡,点击激活会冒泡到取消:

    在这里插入图片描述

    阻止冒泡,点击激活不会冒泡:

    在这里插入图片描述

    事件代理

    • 代码更简洁
    • 减少浏览器内存占用
    • 但是,不要滥用
    • 对于复杂,不好去每个都绑定事件的时候使用

    示例:元素 a 把事件处理委托给自己的父元素 div 去处理

        <div id="div1">
            <a href="#">a1</a>
            <a href="#">a2</a>
            <a href="#">a3</a>
            <a href="#">a4</a>
            <button>加载更多...</button>
        </div>
    	
    	function bindEvent(elem, type, fn) {
            elem.addEventListener(type, fn)
        }
        const div1 = document.getElementById('div1')
        bindEvent(div1, 'click', event => {
            event.preventDefault() // 阻止页面跳转
            const target = event.target
            if(target.nodeName === 'A') {
                alert(target.innerHTML)
            }
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    点击 a1-4 会弹出对话框,点击按钮则不会:

    在这里插入图片描述

    通用事件绑定函数(考虑代理)

    • fn 不能是箭头函数,箭头函数无法被 call
        <div id="div1">
            <a href="#">a1</a>
            <a href="#">a2</a>
            <a href="#">a3</a>
            <a href="#">a4</a>
            <button>加载更多...</button>
        </div>
        <button id="btn1">点击</button>
    
    	// 通用事件绑定函数
        function bindEvent(elem, type, selector, fn) {
            // 如果传入三个参数,把 selector 赋值给 fn,selector 置空
            if (fn == null) {
                fn = selector
                selector = null
            }
            elem.addEventListener(type, event => {
                const target = event.target
                if (selector) {
                    // 代理绑定
                    if (target.matches(selector)) {
                        fn.call(target, event)
                    }
                } else {
                    // 普通绑定
                    fn.call(target, event)
                }
            })
        }
    	
    	// 普通绑定
        const btn1 = document.getElementById('btn1')
        bindEvent(btn1, 'click', function(event) {
            event.preventDefault()
            alert(this.innerHTML)
        })
    
        // 代理绑定
        const div1 = document.getElementById('div1')
        bindEvent(div1, 'click', 'a', function (event) {
            event.preventDefault()
            alert(this.innerHTML)
        })
    
    • 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

    点击 a1-4 会弹出对话框,点击按钮则不会:

    在这里插入图片描述

    不积跬步无以至千里 不积小流无以成江海

    点个关注不迷路,持续更新中…

  • 相关阅读:
    Tabby All configured authentication methods failed
    Docker swarm 管理 secrets
    Redis 入门及应用 ( 五 ) 双写一致性
    Spring Cloud 之OpenFeign
    Qt QCustomPlot介绍
    java计算机毕业设计高校社团管理系统MyBatis+系统+LW文档+源码+调试部署
    2023年8月京东白酒行业数据分析(京东数据开放平台)
    Jetson Nano 系列之:C通过内存映射操作GPIO
    文献速递:肺癌早期诊断---利用低剂量CT扫描的三维概率深度学习系统用于肺癌的检测与诊
    “图片在哪”、“我是temunx”、“变成思维导图用xmindparser”gpt给出文本变字典
  • 原文地址:https://blog.csdn.net/qq_45902692/article/details/126174849