【JS随笔】监听DOM内容改变

2023-11-12

目录

前言

一、addEventListener

        1.示例

二、MutationObserver

1.示例1

2.示例2

总结

参考资料



前言

  今天项目遇到一个需要监听DOM变化,根据DOM的变化情况,来展示不同的内容,于是上网搜索了各种方式,做一下总结,方便下次查看。


一、addEventListener

关于这个API不要查看菜鸟教程中的解释,直接看MDN即可

  1. addEventListener函数说明 :https://developer.mozilla.org/zh-CN/docs/Web/API/EventTarget/addEventListener
  2. addEventListener事件参考:事件参考 | MDN

1.示例

对于DOMNodeInserted事件,我们只需要知道使用函数document.addEventListener传递第一个参数为字符串DOMNodeInserted,第二个参数为事件处理函数。

事件处理函数的第一个参数为事件对象,其中属性target为被插入的对象,根据该对象的各种属性,我们执行我们的各种操作(禁用、删除、增加等等)。
代码如下:

<body>
    <table id="outside">
        <tr>
            <td id="t1">one</td>
        </tr>
        <tr>
            <td id="t2">two</td>
        </tr>
    </table>
    <script>
        // 改变 t2 的函数
        function modifyText() {
            var t2 = document.getElementById("t2");
            if (t2.firstChild.nodeValue == "three") {
                t2.firstChild.nodeValue = "two";
            } else {
                t2.firstChild.nodeValue = "three";
            }
        }
        // 为 table 添加事件监听器
        var el = document.getElementById("outside");
        el.addEventListener("click", modifyText, false);
    </script>
</body>

二、MutationObserver

参考文档MDN MutationObserver - Web API 接口参考 | MDN

基础核心:

  • MutationAbserver
  • MutationAbserverInit
    • attributes: true 【是否监听属性变化】
    • attributeFilter: ['popkey'] | undefined 【监听的属性范围,如果设置为undefined | 没有设置表示监听全部的属性】
    • attibuteOldValue: true 【是否把 回调函数中的MutationRecord.oldValue 对象是否包含了更改前的数据
    • characterData: true 【是否监听 内部子文本节点的数据发生变化】
    • characterDataOldValue: true 【是否把 之前的数据发送给 MutationRrecord】
    • childList: true,【是否 监听子节点的插入/删除】
    • subtree: true 【是否 把监听的范围扩展到内部的全部子孙节点】
  • MutationRecor

        

1.示例1

代码如下:

<body>
    <div id="test"></div>
    <script>
        const targetNode = document.getElementById('test');
        // 观察器的配置(需要观察什么变动)
        const config = { attributes: true, childList: true, subtree: true };
        // 当观察到变动时执行的回调函数
        const callback = function (mutationsList, observer) {
            for (let mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    console.log('有节点发生改变,当前节点的内容是:');
                    console.log(item.target.innerHTML);
                }
                else if (mutation.type === 'attributes') {
                    console.log('修改了'+item.attributeName+'属性');
                }
            }
        };
        // 创建一个观察器实例并传入回调函数
        const observer = new MutationObserver(callback);
        // 以上述配置开始观察目标节点
        observer.observe(targetNode, config);
        // 之后,可停止观察
       // observer.disconnect();
    </script>
</body>

效果如下图所示:

2.示例2

<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>mutationObserver</title>
</head>
<body>
    <div class='parent'>
        原始文本
    </div>

    <script type="text/javascript">

        const el_class_parent = document.querySelector('.parent');
        const el_div = document.createElement('div')
        // 文本节点的data就是文本的内容
        const node_text = el_class_parent.childNodes[0]
        
        // observer 观察者
        // 创建一个观察者
        const observer = new MutationObserver(callback)
        // 事件处理器
        function callback(mutationRecords, observer){
            mutationRecords.forEach(mutationRecord => {
                console.dir(mutationRecord)
                if(mutationRecord.type === "attributes") return console.log('属性发生了变化 target =', mutationRecord.target)
                if(mutationRecord.type === 'childList') return console.log('添加or删除了 childList: ',mutationRecord.target)
                if(mutationRecord.type === 'characterData') return console.log('文本节点的数据发生了变化',mutationRecord.target)
            })
        }

        /*
         * 配置文件
        */
        const config = {
            attributes: true,
            attributeFilter: undefined, /*需要监听的属性名称列表,如果没有表示监听全部的属性*/
            attributeOldValue: true, /*传递之前旧的值给mutationRecord*/
            characterData: true, /*是否监听内部文本节点的数据变化*/
            characterDataOldValue: true, /*mutationRecord 是否包含内部文本节点变化前的数据*/
            childList: true,
            subtree: true /*是否把监听的方位放到节点树中的全部子节点上*/
        }

        observer.observe(el_class_parent, config)

        // 监听内部文本节点的数据变化characterData
        setTimeout(() => {
            node_text.data = 'aaa'
        }, 0)

        // 如果在一个事件循环内设置多个变化
        // 会在callback中接受到多个 mutationRecord
        setTimeout(() => {
            Promise
            .resolve()
            .then(() => {
                console.log('-------------promise 队列执行')
                el_class_parent.setAttribute('path', "promise")
            })

            // 设置属性发生变化
            el_class_parent.setAttribute('path', 'old-path');
            el_class_parent.setAttribute('path', 'new-path')
            
            // 设置内容发生变化
            el_class_parent.innerText = "aaa"

            // 每一次的设置都会调用 callback
            el_class_parent.append(el_div)

            console.error('----------------------设置更改完毕')

            setTimeout(() => {
                console.log('--------------------------------下一次事件循环')
                el_class_parent.setAttribute('path', 'new-path-2')
            },0)

            setTimeout(() => {
                console.log('--------------------------- 下一次事件循环')
                el_div.setAttribute('path', 'div-path')
            }, 0)

        }, 1000)
    </script>
</body>
</html>

总结

addEventListener是W3C的API,历史遗留接口,很多问题,整体来说不推荐使用

MutationObserver是H5的API,从设计和兼容性上都要好的多,如果在开发中,使用该api更合适。

DOM MutationObserver在不影响浏览器性能的状态下响应DOM更改

等待全部脚本任务执行完成后,才会运行,即采用异步方式

不过在Chrome测试中发现,addEventListener有些状态监控不到,MutationObserver可以弥补这种情况。而MutationObserver像是消息队列的实现方式,不能查看运行时堆栈。所以开发过程中根据需要使用不同的api,也可以同时使用两套api达到目的。

参考资料

javascript 监听DOM内容改变事件 https://juejin.cn/post/7025877062430752775
书籍《JavaScript框架设计》https://book.douban.com/subject/27133542/
Chrome设置断点的各种姿势 https://cloud.tencent.com/developer/article/1093731
参考文章:https://blog.csdn.net/kinghzking/article/details/123684377

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【JS随笔】监听DOM内容改变 的相关文章

  • HTMLImageElement 作为 React Child 无效

    我正在尝试异步加载图像 并且仅在加载图像后才将其显示在 React 应用程序中 componentDidMount const img new Image img onload gt this setState originalImage
  • Ext JS - 如何滚动到文本区域的底部

    这是我下面的代码 如何滚动到文本区域的底部 它一定是类似的东西 Ext getCmp output setScrollPosition Ext getCmp output getScrollHeight 这是我的文本区域代码 var myW
  • 计算Javascript中两次点击之间的时间

    我想用 javascript 计算属性的两次点击之间的时间 但我不知道如何 例如 a href click here a 如果用户单击多次 假设 5 秒内 我想显示警报 如果有帮助的话我正在使用 jQuery 我对 javascript 不
  • 在 BIRT 中输入参数后更新数据集查询

    在 BIRT 报告设计中传递参数后 如何更改或更新数据集的查询 详细说明 我有一个如下所示的查询 WHERE 该参数标记可以保存不同的值 在用户输入参数后 它看起来像这样 例如 WHERE column name 1 or WHERE co
  • 禁用 JavaScript 中的右键单击

    当我尝试禁用右键单击时 它不起作用 我尝试使用下面的代码 document onclick function e console log e button if e button 2 e preventDefault return fals
  • 何时不使用承诺[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 在阅读了数十篇关于 es6 Promise 有多伟大以及为什么我们应该实现它们的文章之后 我有这样的感觉 ALL我的 不平凡的 JavaScri
  • 创建 Cookie 时需要帮助

    我有一个名为yes和另一个名叫no
  • Ember.JS - 如何在同一页面中使用多个模型、控制器和视图?

    我主要了解 Ember JS 的基础知识 大多数示例实际上只处理单个控制器和模型以在页面上显示某些内容 我真的很想用 Ember 构建一个完整的 Web 应用程序 所以有人能告诉我如何组织和连接多个控制器 模型和视图到一个页面中吗 例如 如
  • 保存/导出Chrome的JavaScript控制台输入历史记录

    无论如何 我可以保存或导出 JavaScript 控制台的历史记录吗 input 控制台历史记录 在 Google Chrome 中 我不想保存输出或错误 因此将鼠标悬停在控制台框上 右键单击并选择Save as 不是解决方案 我不想每次都
  • 如何改变HTML5视频的播放速度?

    如何更改 HTML5 中的视频播放速度 我查过视频标签的属性 https www w3schools com html html5 video asp在 w3school 但无法做到这一点 根据这个网站 http www chipwreck
  • jQuery 选择器:为什么 $("#id").find("p") 比 $("#id p") 更快

    该页面的作者 http 24ways org 2011 your jquery now with less suck http 24ways org 2011 your jquery now with less suck断言 jQuery
  • 使用 jquery 将字符串数组转换为整数

    我正在尝试将 jquery 中的字符串数组转换为整数数组 这是我的尝试 var cdata data values split each cdata function i l l parseInt l 我认为在这种情况下你不需要使用 Jqu
  • 如何访问另一个 mobx 商店中的 mobx 商店?

    假设以下结构 stores RouterStore js UserStore js index js each of Store jsfiles 是一个 mobx 存储类 包含 observable and action index js只
  • 如何在 e2e AngularJS 测试中进行文件上传?

    在我的一种观点中 我有一个文件上传控件 它支持通过拖放或单击按钮后打开的标准文件对话框上传文件 How to do this in my e2e tests1 1 Just one of the two options will be en
  • 从多维无穷大数组中删除数组元素

    我想删除一个特定元素 例如 我想删除元素id 76在下面的数组中 而且 数组可以无限地组合在一起 这里的问题是我无法刷新页面 因为我使用 Vue js 进行即时操作 如果我能做到这一点 我的下一个问题可能是如何在我现在想要的地方添加一个元素
  • Jquery:选择菜单以显示和隐藏某些div元素

    我正在创建一个选择菜单 根据所选选项显示和隐藏某些 div 像这样的东西
  • 加载另一个 JS 脚本后加载

    这是我的代码 very big js file lots of html stuff 问题是 这些是异步加载的 有没有办法等待第二个脚本直到第一个脚本加载 如果您使用 jQuery 有一个非常简单的方法可以通过获取脚本 https api
  • ng-model 和值组合不适用于输入文本框

    我有两个输入文本框 我需要组合在两个文本框中输入的值并将其显示在第三个文本框中 如果我只使用value在第三个文本框中 Box 1
  • 如何在 SVG 元素上使用箭头标记?

    我需要在 d3 js 中创建一个箭头 但我找到的只是带有节点图的示例 我需要的是简单地制作一个从 A 点到 B 点的箭头 我尝试实现以下示例中的部分代码 http bl ocks org 1153292 http bl ocks org 1
  • Bootstrap 3 / 显示模式不适用于 javascript 方式

    我用Modal http getbootstrap com javascript modalsBootstrap 3 0 的功能 我有这个代码 a href myNestedContent Open the modal containing

随机推荐

  • Arthas使用方法

    1 简介 Arthas 是Alibaba开源的Java诊断工具 安装在系统所在服务器 可以帮助开发人员或者运维人员查找问题 分析性能 bug追踪 下载路径 https arthas aliyun com arthas boot jar 2
  • 功能视图的组成

    功能视图是构建联邦学习系统所需功能的技术中立的视图 功能视图描述了支持联邦学习活动所必需功能的分布 定义了功能之间的依赖关系 功能视图涵盖的联邦学习内容如图 包括 功能组件 功能层 跨层功能 功能组件是参与某一活动所需的 能实现的功能构件
  • 与OpenAI的30 天

    30 天 我计划在 GitHub 上测试开源 Ai 项目 并学习如何自己构建一个项目 这些帖子会很短 重点是了解您可以使用 Ai 创造什么以及需要准备什么 图像是使用midjourney生成的 我一直在收集由像你我这样的开发人员创建的 30
  • react-从0到1新建react项目

    目录 1 脚手架创建项目 2 分析目录 3 动态写入值 编辑 4 引入组件 编辑 5 组件传值 6 控制组件传值的类型 类型校验 7 组件插槽 8 函数组件和类组件 9 添加事件 10 引入state 在页面上响应式改变值 编辑 11 子组
  • 【C语言】C语言的495个问题

    文章目录 1 声明和初始化 基本类型 1 1 各类型区别 1 2 为什么不精确定义标准类型的大小 1 3 因为C没有精确定义标准类型大小 那么用typedef定义int16和int32是否能解决问题呢 1 4 新64位机上64位类型是什么样
  • android下m、mm、mmm编译命令的使用

    通过查看android源码目录下的build envsetup sh文件 可知 m Makes from the top of the tree mm Builds all of the modules in the current dir
  • C#编程基础(万字详解,这一篇就够了)

    C 及其开发环境简介 C 概述 C 的编程功能 C 与 Net的关系 Net C C 的集成开发环境 Windows上编写C 程序 Linux Mac OS上编写C 程序 运行第一个HelloWorld程序 C 基本语法 程序实例 C 基本
  • java mail 添加附件以及邮件中穿插图片方法

    部分代码 创建邮件中的附件 param filepath 附件的路径 return 生成附件的对象 throws Exception 测试 filepath e 测试 tomcat png e盘下的tomcat图片 public stati
  • 基本的垃圾回收算法总结

    Java虚拟机中的垃圾回收机制的是虚拟机的灵魂所在 下面介绍下虚拟机中的主要回收算法 引用计数法 实现 对于实例化的一个对象O 只要有任何一个其他的对象引用O O的引用计数器就加一 当引用失效的情况下 引用计数器减一 优点 实现简单 缺点
  • 全国各大城市的经纬度表,留着以后做查询库用

    安徽省合肥的经纬度北纬31 52东经117 17 安徽省安庆的经纬度北纬30 31东经117 02 安徽省蚌埠的经纬度北纬32 56东经117 21 安徽省亳州的经纬度北纬33 52东经115 47 安徽省巢湖的经纬度北纬31 36东经11
  • css 卡片翻转效果实现

    直接贴代码
  • Vue 引入高德地图 vue-amap

    一 在高德开发平台 获取Key 已有可跳过 高德开发者平台 链接地址 1 控制台 我的应用 创建应用 添加key 创建应用 新建应用 选择web端 JS平台 last 到这里的 key 就有了 还得到了一个安全密钥 二 引入vue amap
  • 5G应用标志着移动互联网新时代真正到来

    5G网络普及后很可能实现已经多次被我们所畅想的万物互联 通过网络把家用电视 冰箱 洗衣机 空调等连接起来 再通过一个软件来进行控制 5G超高的网速 超低的延迟将会使无人驾驶 无人机作业 远程医疗技术等步入成熟阶段 因此 5G的应用标志着移动
  • TypeScript 在 vue 中的使用

    本文主要介绍 TypeScript 在 vue 中的使用 还有一些j注释起来的 js 代码做对照 参考链接 合成 API 的 TypeScript vue3中配合使用TS 还需要额外安装一个vscode插件 Typescript Vue P
  • 基于snooplog分析蓝牙连接过程,进一步学习蓝牙协议栈

    一 什么是BT snoop log 首先问题 1 为什么远端发来的消息没有收到 2 为什么搜索不到设备 3 为什么连不上 4 总之 研发过程中会遇到很多奇奇怪怪的问题 我们无法通过现象去分析原因 也不可能再过一遍代码吧 这时候需要再某些代码
  • 期货交易,一些你不得不知道的技巧

    众所周知 期货市场变化莫测 既有风险 又兼具了高回报 因此也被誉为 21世纪冒险者的游戏 虽然期货投资受市场 政治形势 经济发展等因素的影响 但作为一个成熟的交易模式 期货依然有着很大的魅力 既可以做长线 也可以短线为王 但无论采用何种交易
  • 如何建设水利数字孪生流域

    数字孪生流域是以物理流域为单元 时空数据为底座 数学模型为核心 水利知识为驱动 对物理流域全要素和水利治理管理活动全过程的数字化映射 智能化模拟 实现与物理流域同步仿真运行 虚实交互 迭代优化 建设水利数字孪生流域 重点包括以下几件事 获取
  • nginx日志access.log error.log按天生成存储,定时删除日志

    bin bash function cut nginx log files for lnmp v0 5 and v0 6 author http lnmp org set the path to nginx log files log fi
  • Qt多线程基础(一)线程同步之互斥锁同步

    一 直接使用QMutex进行同步 创建线程方法 继承自QThread 重写void run 函数 调用成员start 启动线程 start 中可加入优先级参数 互斥锁同步方法 void run 函数中使用QMutex来实现同步 当多个线程访
  • 【JS随笔】监听DOM内容改变

    目录 前言 一 addEventListener 1 示例 二 MutationObserver 1 示例1 2 示例2 总结 参考资料 前言 今天项目遇到一个需要监听DOM变化 根据DOM的变化情况 来展示不同的内容 于是上网搜索了各种方