去除/高亮页面元素的JS脚本

您所在的位置:网站首页 css选择器选择前几个 去除/高亮页面元素的JS脚本

去除/高亮页面元素的JS脚本

2023-05-31 18:17| 来源: 网络整理| 查看: 265

最近开发了一个基于TamperMonkey的JS脚本,其主要功能为去除特定页面中的广告、Header等无效信息元素,并根据逻辑高亮其中重要信息元素。

Github

从解决需求角度出发,常见的去除页面中的广告可以通过CSS植入,并利用样式选择器将广告元素的display属性设置为none。但需要根据逻辑高亮元素(如经过元素内文本排序后,对前n位进行高亮),简单的CSS植入无法满足这个需求。因此最后采用了TamperMonkey执行JS脚本的方案,利用JS操纵DOM元素来达到去除/高亮元素的目的。

目标页面采用了懒加载处理,可见范围外的元素不会提前加载。而TamperMonkey的内置执行时机,只能在页面开始加载或加载完成后执行一次。对于页面加载完成后,动态新加载的元素,无法完成功能。

@run-at Timing document-start as fast as possible document-body body element exists document-end when or after the DOMContentLoaded event was dispatched document-idle after the DOMContentLoaded event was dispatched context-menu it is clicked at the browser context menu

由于页面的动态加载,需要多次执行目标函数。一种做法是,通过setInterval函数来指定目标函数每隔一段时间执行。这样的优点是编码简单,缺点是消耗系统资源,不太优雅。页面动态加载会导致DOM元素的增加或减少,因此更为优雅的做法是注册事件,当页面元素发生变化时,重新执行目标函数,这就用到了MutationObserver。

MutationObserver

MutationObserver可以检测页面元素属性变化、子节点的添加或删除、文本内容的变化等。

MutationObserver 的使用步骤如下:

创建一个 MutationObserver 对象,传入一个回调函数作为参数,该回调函数将在 DOM 树变化时被调用。在此问题中,callback就是去除/高亮页面元素的函数。

1const observer = new MutationObserver(callback);

使用 observe 方法开始监视 DOM 元素的变化,传入要观察的 DOM 元素以及要观察的变化类型的配置对象。

1observer.observe(target, options);

target 是要观察的 DOM 元素,一般为document.documentElement,表示监视整个页面文档的元素变化。options 是一个配置对象,用于指定要观察的变化类型。此处为{childList: true, subtree: true},表示检测target以及其子节点的元素变化。如果不设置,默认只监测target本身,子节点的添加和减少不会被监测到。

在回调函数中处理 DOM 变化的情况。

123456function callback(mutationsList, observer) { // mutationsList 是一个 MutationRecord 对象的数组,包含了发生的 DOM 变化 // observer 是当前的 MutationObserver 对象

// 在这里处理 DOM 变化的情况}

回调函数可以接收到发生变化的元素的信息。可以通过判断改变的是哪个元素,来具体执行去除/高亮的动作。在本项目中,为了偷懒并没有在此进行判断。

引发的问题

在采用MutationObserver之后,页面出现了无法加载的情况。通过调试器查看到,目标函数被反复调用,整个页面陷入卡死的状态。猜测是页面元素发生变动,调用了目标函数后,目标函数也改变了页面元素(但是我的代码里没有啊?),反复触发了MutationObserver的目标函数,形成了递归死循环。为了解决这个问题,了解了函数防抖和函数节流。

函数防抖和函数节流

函数防抖和函数节流都是用于限制某个函数的执行频率。如果函数调用的频率小于设定的阈值,那么是否采用函数防抖和函数节流对程序执行没有任何区别。

防抖的基本思想是在一定的时间间隔内,只执行最后一次触发事件的处理函数,忽略在此时间间隔内的其他触发事件。与函数防抖不同,函数节流是在一定的时间间隔内,定期执行事件处理函数。

函数防抖就像拍卖,拍卖成功(目标函数执行)会在敲三锤(一定间隔后)执行,一旦在敲三锤前进行了竞拍(再次调用用防抖包裹的目标函数),那么间隔会被重置。

函数节流就像大学抢浴室。一个人进了浴室(调用用节流包裹的目标函数),其他人再想进去(再次调用用节流包裹的目标函数)就不行,必须等这个人洗完(一定间隔),一旦他洗完(目标函数执行),所有人都可以再次抢浴室(调用用节流包裹的目标函数)。从某种角度,这和锁机制很像,被上锁的对象为计时器。只有获得计时器的调用才会被真正执行。

123456789101112131415function debounce(func, delay) { let timerId; // 记录定时器的ID

return function(...args) { // 如果已存在定时器,则先清除之前的定时器 if (timerId) { clearTimeout(timerId); } // 创建新的定时器,延迟执行 func 函数 timerId = setTimeout(() => { func.apply(this, args); // 执行 func 函数 timerId = null; // 清空定时器ID }, delay); };}

1234567891011function throttle(func, delay) { let lastTime = 0; // 上次执行的时间戳

return function (...args) { const now = Date.now(); // 当前时间戳 if (now - lastTime >= delay) { // 判断当前时间与上次执行的时间间隔是否超过指定的等待时间 func.apply(this, args); // 执行函数 lastTime = now; // 更新上次执行的时间戳 } }}

函数防抖和节流都能限制函数被调用的频率,区别是什么时候能再次被调用,防抖是从多次小于设定间隔的连续调用的最后一次开始计算,而节流是从第一次调用开始计算,因此相同条件下,节流可以更快地进行第二次有效调用。

总的来说,函数防抖适合在需要等待一段时间后再执行函数的场景。如果目标函数不需要等待可以立即执行,则使用节流即可。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3