关键技术
MutationObserver
MutationObserver使用来监测某个范围内DOM的变动,如节点的增减、属性的变动,文本节点的变化等。相当于DOM的改变就会触发MutationObserver这个事件,但是这个事件是异步触发的,会把DOM的变动封装成一个数组进行统一更新的,这点和react中的setState非常相像。
构造函数
var observer = new MutationObserver(function (mutations, observer) {
mutations.forEach(function(mutation) {
console.log(mutation);
});
})
在调用时,观察者对象会传给该函数两个参数:
-
MutationObserver接受一个callback参数,用来处理节点变化的回调函数,返回两个参数,mutations和observer。
-
mutations:节点变化记录列表
-
observer:MutationObserver的实例对象。
方法
MutationObserver对象有三个方法,分别如下:
-
observe:设置观察目标,接受两个参数,target:观察目标,options:通过对象成员来设置观察选项
-
disconnect:阻止观察者观察任何改变
-
takeRecords:清空记录队列并返回里面的内容
observe方法中常用的options参数有已下几个选项:
-
childList:设置true,表示观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化
-
attributes:设置true,表示观察目标属性的改变
-
characterData:设置true,表示观察目标数据的改变
-
subtree:设置为true,目标以及目标的后代改变都会观察
使用示例
现在有一个id为target的节点
<div id='target' class='block'>
</div>
对该dom进行监听并测试
var target=document.getElementById('target');
var i=0
var observe=new MutationObserver(function (mutations,observe) {
i++
});
observe.observe(target,{ childList: true});
target.appendChild(docuemnt. createElement ('span'));
target.appendChild(docuemnt. createElement ('div'));
console.log(i) //1
录制回放操作的简单实现
初始思路:使用MutationObserver监听整个页面,每当有页面变动,则将页面的html转换成图片进行队列存储,回放用户操作即不停从队列中取出元素展示
Html转Canvas
这里我们直接使用html2canvas这个第三方库官方地址,基于html2canvas.js可将一个元素渲染为canvas,只需要简单的调用html2canvas(element[, options]),下列html2canvas方法会返回一个包含有canvas元素的promise:
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});
Canvas转Img
上一步生成的canvas即为包含目标元素的canvas元素对象。实现保存图片的目标只需要将canvas转image即可。通过canvas的toDataURL方法将canvas输出为data: URI类型的图片base64地址,再将该图片地址赋值给元素的src属性即可。
示例
<canvas id="canvas" width="5" height="5">
</canvas>
获取该图片,直接可以用toDataURL转成图片,默认为 PNG 格式
var canvas = document.getElementById("canvas");
var dataURL = canvas.toDataURL();
console.log(dataURL);
// "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNby...
最后,通过定时器将img不停的插入到img标签的src中,实现回放的效果。
Canvas在高分屏中一些缺陷的解决方法
Canvas在高分屏中绘制图片会有模糊的效果,其实不只是绘制图片时会出现模糊的问题,高清屏的设备中任何绘制在 canvas 中的图形(包括文字)都会出现模糊的问题。
这是因为HIDPI的屏幕上的像素实际上是逻辑像素,我们如果当成正常的像素(css中设置的像素)使用它,如我们在css中设置100px时,在例如iphone4S(devicePixelRatio为2)上,实际渲染的是200px的物理像素。所以当我们向这种高分辨率的屏幕添加img的时候,我们的图像及其他一些图形文字都会受到devicePixelRatio的影响会变得模糊。
解决方法很简单,就是将 canvas 的高和宽分别乘以 devicePixelRatio将其放大,然后又用 CSS 将高和宽限制成初始的大小。
Demo效果
这里为了简化操作,做捉了两个按钮做添加和删除元素,实际情况中,不仅需要对dom节点的操作进行监听,例如用户的点击、停留、轨迹等行为数据都需要进行采集分析。
方案优化
在Web中, 图形图像的操作以及存储会消耗大量的性能, 通过使用html快照来替代图像快照可以大幅的提高性能以达到生成可用状态,但是需要做很多的处理,当我们存储的是html的快照链时,想要在客户端进行用户操作回放,我们需要构建沙盒环境对html重新进行渲染,有一些工具如parse5可以进行html的序列化和解析操作,“视频回放”其实就是 HTML DOM 的变化增量及快照。
在html的解析过程中需要要对dom快照进行一点的处理,如:
-
禁止表单提交
-
禁止跳转、window.open等操作
-
js脚本的执行(因为我们只是需要dom结构的变化)等
-
浏览器端存一定量的增量快照后再一起发送到服务端,减少网络开销;也包括多次增量之后再进行一次全量,对齐真实状态。
-
数据脱敏
-
通过 DocumentFragment 提高平台回放效率。
可以参考开源方案RRWeb:github.com/rrweb-io/rr…
基于上述技术还可以实现哪些小功能(思路)
网页中长按保存截图(针对移动端)
捕捉长按的操作,然后通过我们上面的,实现转canvas转img的操作
网页中实现撤销操作
记录用户的每次的dom操作放到一个栈中,每次用户触发撤销操的时候从栈中取出一个元素,可以还原上次的dom结构,从而实现了撤销的操作
有关动态显示的部分
例如根据文本内容是否超出来动态控制是否显示Tooltip,文本末尾显示其他内容等