5种 observe 和 sendbecan
# 5 种 Observer:
# IntersectionObserver:监听元素可见性变化,常用来做元素显示的数据采集、图片的懒加载
# MutationObserver:监听元素属性和子节点变化,比如可以用来做去不掉的水印
let canvas = document.createElement('canvas')
canvas.id = '__canvas'
canvas.width = '180' // 每个水印的宽高
canvas.height = '150'
let ctx = canvas.getContext('2d')
ctx.fillStyle = 'rgba(150, 150, 150, 0.5)'
ctx.rotate((25 * Math.PI) / 180) // 偏转的角度
ctx.fillText('originDu?', 30, 20) // 绘制文本 绘制开始位置
let src = canvas.toDataURL('image/png')
// 水印容器
let waterMaskDiv = document.createElement('div')
waterMaskDiv.style.position = 'fixed'
waterMaskDiv.style.zIndex = '-1'
waterMaskDiv.id = '__water-mark'
waterMaskDiv.style.top = '0'
waterMaskDiv.style.left = '0'
waterMaskDiv.style.height = '100%'
waterMaskDiv.style.width = '100%'
waterMaskDiv.style.pointerEvents = 'none'
waterMaskDiv.style.backgroundImage = 'URL(' + src + ')'
// 水印节点插到body下 可以通过层级控制节点层次
document.body.appendChild(waterMaskDiv)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 禁止修改水印节点
let targetNode = document.querySelector('#__water-mark')
let config = {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeOldValue: true,
characterDataOldValue: true
}
const mutationCallback = mutationList => {
for (let mutation of mutationList) {
let type = mutation.type
switch (type) {
case 'childList':
console.log('节点被删除或添加')
break
case 'attributes':
console.log(`${mutation.attributeName}属性修改了`)
break
case 'subtree':
console.log('子树被修改')
break
default:
break
}
}
}
// 创建 MutationObserver 实例
let observer = new MutationObserver(mutationCallback)
// 开始监控目标节点
observer.observe(document.body, config)
// 停止监控
// observer.disconnect()
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
在检测到修改的时候,可以对比被修改的元素的ID,如果是水印的ID,这时候可以删除水印div后重新执行第一步的插入操作,以达到避免水印被修改的目的
# ResizeObserver:监听元素大小变化,window.addEventListener("resize",callback)
只能监听浏览器大小变化
还有两个与元素无关的:
# PerformanceObserver:监听 performance 记录的行为,来上报数据
# ReportingObserver:监听过时的 api、浏览器的一些干预行为的报告,可以让我们更全面的了解网页 app 的运行情况
# sendBeacon
上报方式是利用img标签的src属性发送请求,例如:
(new Image).src = `/haopv.gif?a=xx&b=xxx`
因为日志上报不需要响应处理,只需要把数据发过去就行。并且大部分接收日志的服务器地址与业务方可能不是一个部门,甚至可能不是一个公司,所以会涉及到跨域问题。使用img标签的src属性既可以把数据发送给服务端又不需要接收响应,同时解决了跨域问题,所以是目前比较受欢迎的日志上报实现方式。
日志上报并不是应用的主要功能逻辑,也就是说,日志上报是低优先级的,它不应该与其他高优先级操作(例如:获取关键资源、输入响应、运行动画等)去竞争网络与计算资源(通俗的说就是日志上报行为不应该影响业务逻辑,不应该占用业务计算资源)。但是这种单向请求又负责传递应用的错误与性能数据,所以我们必须要确保它会被交付到服务端。
我们的交付行为有可能会被插入到正在忙碌工作的事件循环中,从而抢占了其他高优先级的任务的资源,因为JS是单线程的。这有可能会损害用户体验。
也就是说,使用 sendBeacon 是因为确保日志数据会被交付的同时,尽可能地减少与其他关键操作的资源争用
sendBeacon 可用于记录在页面上停留的时间,日志上报等
监听页面在关闭或者刷新时 beforeunload 或者 页面正在被卸载前unload 触发;
Beacon API 用于将少量数据通过 post 请求发送到服务器;
Beacon 是非阻塞请求,不需要响应。
用法
navigator.sendBeacon(url, data);
url:表示 data 将要被发送到的网络地址;
data:将要发送的 ArrayBufferView 或 Blob, DOMString 或者 FormData 类型的数据。
返回值:当用户代理成功把数据加入传输队列时,sendBeacon() 方法将会返回 true,否则返回 false。
支持的类型:text/plain:发送普通字符串
目前在 Beacon 中最常用的形式:
navigator.sendBeacon(url, JSON.stringify(data));
- 01
- 2023/07/03 00:00:00
- 02
- 2023/04/22 00:00:00
- 03
- 2023/02/16 00:00:00