使用rrweb 回溯(页面录制,到播放)

使用Rrweb 指南

例子:如果例子播放不了。可以到这来观看→

屏幕录制2022-06-19下午10.28.01

一、录制rrweb请添加图片描述

播放rrweb
请添加图片描述
录制的json数据
请添加图片描述

各位可以试试

rrweb是什么?
rrweb 是 ‘record and replay the web’ 的简写,用来录制并回放任意 web 界面中的用户操作。

⚠️注意:rrweb不支持 IE11 以下,如需兼容(https://caniuse.com/#feat=mutationobserver)访问这个连接

二、Rrweb 功能
  • 记录用户使用产品的方式并加以分析,进一步优化;
  • 采集用户遇到的bug的操作路径,予以复现;
  • 回溯用户的行为,可作为证据存储;
  • 录制体积更小,清晰度无损的演示视频;
  • 记录自动化测试的执行情况;
三、开始安装
方式1、直接通过外部全局引入
推荐通过 jsdelivr 的 CDN 安装:
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.js"></script>

也可以在 URL 中指定具体的版本号,例如:

src="https://cdn.jsdelivr.net/npm/rrweb@0.7.0/dist/rrweb.min.js"></script>

仅引入录制部分
rrweb 代码分为录制和回放两部分,大多数时候用户在被录制的应用中只需要引入录制部分代码,同样可以通过 CDN 安装:

<script src="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/record/rrweb-record.min.js"></script>
其它按需引入方式

除了仅包含录制代码的 record/rrweb-record-min.js 之外,rrweb 还提供了其它多种可选的打包文件。所有包含 .min 的文件为同名文件的压缩版。

包含录制、回放、压缩数据、解压缩数据
rrweb-all.js
rrweb-all.min.js
包含录制、回放
rrweb.js
rrweb.min.js
回放所需的样式文件
rrweb.min.css
录制
record/rrweb-record.js
record/rrweb-record.min.js
压缩数据
record/rrweb-record-pack.js
record/rrweb-record-pack.min.js
回放
replay/rrweb-replay.js
replay/rrweb-replay.min.js
解压缩数据
replay/rrweb-replay-unpack.js
replay/rrweb-replay-unpack.min.js
兼容性

由于使用 MutationObserver API,rrweb 不支持 IE11 以下的浏览器。可以从这里找到兼容的浏览器列表。

方式2、录制使用npm 安装
npm install --save rrweb
四、快速开始
录制
如果通过 <script> 的方式仅引入录制部分,那么可以访问到全局变量 rrwebRecord,它和全量引入时的 rrweb.record 使用方式完全一致,以下示例代码将使用后者。
rrweb.record({
  emit(event) {
    // 用任意方式存储 event
  },
});

rrweb 在录制时会不断将各类 event 传递给配置的 emit 方法,你可以使用任何方式存储这些 event 以便之后回放。

调用 record 方法将返回一个函数,调用该函数可以终止录制:
//例子1
let stopFn = rrweb.record({
  emit(event) {
    if (events.length > 100) {
      // 当事件数量大于 100 时停止录制
      stopFn();
    }
  },
});

//一个更接近实际真实使用场景的示例如下:
//例子2
let events = [];

rrweb.record({
  emit(event) {
    // 将 event 存入 events 数组中
    events.push(event);
  },
});

// save 函数用于将 events 发送至后端存入,并重置 events 数组
function save() {
  const body = JSON.stringify({ events });
  events = [];
  fetch('http://YOUR_BACKEND_API', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body,
  });
}

// 每 10 秒调用一次 save 方法,避免请求过多
setInterval(save, 10 * 1000);
配置参数

rrweb.record(config) 的 config 部分接受以下参数

key默认值功能
emit必填获取当前录制的数据
checkoutEveryNth-每 N 次事件重新制作一次全量快照
checkoutEveryNms-每 N 毫秒重新制作一次全量快照
blockClass‘rr-block’字符串或正则表达式,可用于自定义屏蔽元素的类名
blockSelectornull所有 element.matches(blockSelector)为 true 的元素都不会被录制,回放时取而代之的是一个同等宽高的占位元素
ignoreClass‘rr-ignore’字符串或正则表达式,可用于自定义忽略元素的类名
maskTextClass‘rr-mask’字符串或正则表达式,可用于自定义忽略元素 text 内容的类名
maskTextSelectornull所有 element.matches(maskTextSelector)为 true 的元素及其子元素的 text 内容将会被屏蔽
maskAllInputsfalse将所有输入内容记录为 *
maskInputOptions{ password: true }选择将特定类型的输入框内容记录为 *类型
maskInputFn-自定义特定类型的输入框内容记录逻辑
maskTextFn-自定义文字内容的记录逻辑
slimDOMOptions{}去除 DOM 中不必要的部分类型
inlineStylesheettrue是否将样式表内联
hooks{}各类事件的回调类型
packFn-数据压缩函数,详见优化存储策略
sampling-数据抽样策略,详见优化存储策略
recordCanvasfalse是否记录 canvas 内容
inlineImagesfalse是否将图片内容记内联录制
collectFontsfalse是否记录页面中的字体文件
userTriggeredOnInputfalse什么是 userTriggered
plugins[]加载插件以获得额外的录制功能. 什么是插件?
隐私

页面中可能存在一些隐私相关的内容不希望被录制,rrweb 为此做了以下支持:

在 HTML 元素中添加类名 .rr-block 将会避免该元素及其子元素被录制,回放时取而代之的是一个同等宽高的占位元素。
在 HTML 元素中添加类名 .rr-ignore 将会避免录制该元素的输入事件。
所有带有.rr-mask类名的元素及其子元素的 text 内容将会被屏蔽。
input[type="password"] 类型的密码输入框默认不会录制输入事件。

配置中还有更为丰富的隐私保护选项。
重新制作快照

默认情况下,要重放内容需要所有的 event,如果你不想存储所有的 event,可以使用checkout配置。

多数时候你不必这样配置。但比如在页面错误发生时,你只想捕获最近的几次 event ,这里有一个例子:


// 使用二维数组来存放多个 event 数组
const eventsMatrix = [[]];

rrweb.record({
  emit(event, isCheckout) {
    // isCheckout 是一个标识,告诉你重新制作了快照
    if (isCheckout) {
      eventsMatrix.push([]);
    }
    const lastEvents = eventsMatrix[eventsMatrix.length - 1];
    lastEvents.push(event);
  },
  checkoutEveryNth: 200, // 每 200 个 event 重新制作快照
});

// 向后端传送最新的两个 event 数组
window.onerror = function () {
  const len = eventsMatrix.length;
  const events = eventsMatrix[len - 2].concat(eventsMatrix[len - 1]);
  const body = JSON.stringify({ events });
  fetch('http://YOUR_BACKEND_API', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body,
  });
};

由于 rrweb 使用了增量快照机制,我们不能指定数量来捕获最近的几次 event。上面这个例子,你可以拿到最新的 200-400 个 event 来发送给你的后端。

类似的,你可以通过配置 checkoutEveryNms 来捕获最近指定时间的 event :



// 使用二维数组来存放多个 event 数组
const eventsMatrix = [[]];

rrweb.record({
  emit(event, isCheckout) {
    // isCheckout 是一个标识,告诉你重新制作了快照
    if (isCheckout) {
      eventsMatrix.push([]);
    }
    const lastEvents = eventsMatrix[eventsMatrix.length - 1];
    lastEvents.push(event);
  },
  checkoutEveryNms: 5 * 60 * 1000, // 每5分钟重新制作快照
});

// 向后端传送最新的两个 event 数组
window.onerror = function () {
  const len = eventsMatrix.length;
  const events = eventsMatrix[len - 2].concat(eventsMatrix[len - 1]);
  const body = JSON.stringify({ events });
  fetch('http://YOUR_BACKEND_API', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body,
  });
};

在上面的例子中,你最终会拿到最新的 5-10 分钟的 event 来发送给你的后端。

回放

回放时需要引入对应的 CSS 文件:



<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/rrweb@latest/dist/rrweb.min.css"
/>
//再通过以下 JS 代码初始化 replayer:

const events = YOUR_EVENTS;

const replayer = new rrweb.Replayer(events);
replayer.play();


//使用 API 控制回放

const replayer = new rrweb.Replayer(events);

// 播放
replayer.play();

// 从第 3 秒的内容开始播放
replayer.play(3000);

// 暂停
replayer.pause();

// 暂停至第 5 秒处
replayer.pause(5000);

配置参数

可以通过 new rrweb.Replayer(events, options) 的方式向 rrweb 传递回放时的配置参数,具体配置如下:

key默认值功能
speed1回放倍速
rootdocument.body回放时使用的 HTML 元素
loadTimeout0加载异步样式表的超时时长
skipInactivefalse是否快速跳过无用户操作的阶段
showWarningtrue是否在回放过程中打印警告信息
showDebugfalse是否在回放过程中打印 debug 信息
blockClass‘rr-block’需要在回放时展示为隐藏区域的元素类名
liveModefalse是否开启直播模式
insertStyleRules[]可以传入多个 CSS rule string,用于自定义回放时 iframe 内的样式
triggerFocustrue回放时是否回放 focus 交互
UNSAFE_replayCanvasfalse回放时是否回放 canvas 内容,开启后将会关闭沙盒策略,导致一定风险
mouseTailtrue是否在回放时增加鼠标轨迹。传入 false 可关闭,传入对象可以定制轨迹持续时间、样式等,配置详见类型
unpackFn-数据解压缩函数,详见优化存储策略
logConfig-console logger 数据播放设置,详见console 录制和播放
plugins[]加载插件以获得额外的回放功能. 什么是插件?

使用 rrweb-player
rrweb 自带的回放只提供所有的 JS API 以及最基本的 UI,如果需要功能更强的回放播放器 UI,可以使用 rrweb-player。

回放安装

rrweb-player 同样可以使用 CDN 方式安装:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/style.css"
/>
<script src="https://cdn.jsdelivr.net/npm/rrweb-player@latest/dist/index.js"></script>

或者通过 npm 安装:

npm install --save rrweb-player
import rrwebPlayer from 'rrweb-player';
import 'rrweb-player/dist/style.css';

使用

通过 props 传入 events 数据及配置项


new rrwebPlayer({
  target: document.body, // 可以自定义 DOM 元素
  // 配置项
  props: {
    events,
  },
});

配置项参数

key默认值功能
events[]包含回放所需的数据
width1024播放器宽度
height576播放器高度
autoPlaytrue是否自动播放
speedOption[1, 2, 4, 8]倍速播放可选值
showControllertrue是否显示播放器控制 UI
tags{}可以以 key value 的形式展示自定义事件在时间轴上的颜色
-其它所有 rrweb Replayer 的配置参数均可透传

事件

开发者可能希望监听回放时的各类事件,例如在跳过无用户操作的时间时给用户一些提示。

在这里插入代码片


rrweb 的 Replayer 提供了 on API 用于提供该功能

const replayer = new rrweb.Replayer(events);
replayer.on(EVENT_NAME, (payload) => {
  ...
})

其包含的事件如下:

事件类型描述
start回放开始-
pause回放暂停-
finish回放完成-
resize回放视图大小发生变化{ width, height }
fullsnapshot-rebuilded全量快照完成重建event
load-stylesheet-start开始加载远端样式表-
load-stylesheet-end加载远端样式表完成-
skip-start开始跳过无用户操作时间{ speed }
skip-end结束无用户操作时间{ speed }
mouse-interaction回放鼠标交互事件{ type, target }
event-cast回放event event
custom-event回放自定义事件event
使用 rrweb-player 时,也可以通过 addEventListener API 使用相同的事件功能,并且会获得 3 个额外的事件:
事件类型描述
ui-update-current-time当前回放时间点{ payload }
ui-update-player-state当前回放状态{ payload }
ui-update-progress当前回放百分比{ payload }
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
好的,下面是使用回溯法实现的Java代码: ```java public class Main { private static int[] nums = {5, 5, 5, 5, 5, 10, 10, 10, 10, 10}; private static boolean[] used = new boolean[10]; private static boolean found = false; public static void main(String[] args) { backtrack(0, 0, 0); if (!found) { System.out.println("No solution found."); } } private static void backtrack(int index, int sum1, int sum2) { if (found || sum2 > sum1 || sum1 > 25) { return; } if (index == 10) { found = true; printSolution(); return; } for (int i = 0; i < 10; i++) { if (!used[i]) { used[i] = true; if (i < 5) { backtrack(index + 1, sum1 + nums[i], sum2); } else { backtrack(index + 1, sum1, sum2 + nums[i]); } used[i] = false; } } } private static void printSolution() { System.out.println("Solution found:"); for (int i = 0; i < 10; i++) { if (i < 5) { System.out.printf("%d元 ", nums[i]); } else { System.out.printf("%d元 ", nums[i]); } } System.out.println(); } } ``` 在这个代码中,我们使用了一个 `nums` 数组来表示10个人拿的钱的面额,使用一个 `used` 数组来记录哪些人已经被选择了。`backtrack` 函数用来进行回溯,其中 `index` 参数表示当前正在处理第几个人,`sum1` 参数表示前半段人的总金额,`sum2` 参数表示后半段人的总金额。回溯的过程中,我们枚举每个人,如果这个人没有被选择过,就尝试选择他,然后进入下一层递归。如果已经找到了解决方案,就直接返回。如果后半段人的总金额已经大于前半段人的总金额,或者前半段人的总金额已经大于25元,也直接返回。如果已经处理完了10个人,就说明找到了一个解决方案,打印出来,并设置 `found` 为 true。在打印解决方案时,我们只需要按照 `nums` 数组的顺序打印出来就可以了。 注意,在 `backtrack` 函数中,我们只需要考虑前半段人和后半段人的金额,不需要考虑具体哪些人拿了哪些钱。这是因为题目只要求我们找到一种排队方案,不需要具体到每个人的钱。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值