您的位置:首页 > 教育 > 培训 > 宁波企业网站制作公司_创业商机网农村_seo论坛_自己建立网站步骤

宁波企业网站制作公司_创业商机网农村_seo论坛_自己建立网站步骤

2024/12/26 6:27:15 来源:https://blog.csdn.net/m0_74824002/article/details/144706320  浏览:    关键词:宁波企业网站制作公司_创业商机网农村_seo论坛_自己建立网站步骤
宁波企业网站制作公司_创业商机网农村_seo论坛_自己建立网站步骤

背景

公司需要对用户的页面交互进行可回溯记录,固使用rrweb进行需求实现;

介绍

rrweb 全称 ‘record and replay the web’,是当下很流行的一个录制屏幕的开源库。与我们传统认知的录屏方式(如 WebRTC)不同的是,rrweb 录制的不是真正的视频流,而是一个记录页面 DOM 变化的 JSON 数组,因此不能录制整个显示器的屏幕,只能录制浏览器的一个页签。

rrweb的github地址:rrweb/guide.zh_CN.md at master · rrweb-io/rrweb · GitHub

功能实现

rrweb 提供了一个基于 fflate 的简单压缩函数,在提交录制中可以作为packFn传入使用。

可以将录制流程分为不同的节点(stepIndex),与服务端商议好进行时间轴排序存储

import { record, pack, unpack } from 'rrweb'
import { saveTCDataByXhr, saveTCDataByBeacon, getTcKey, saveTCDataByFetch } from '@/api/record'/*** 开始屏幕录制*/
export function startRecord() {if (typeof window.stopRecordFn === 'function') {window.stopRecordFn()}window.screenRecords = []console.log('=========== Record Start ==========')const stopFn = record({emit(event) {window.screenRecords.push(event)},packFn: pack, // rrweb 内包含了基于 fflate 的简单压缩 rrweb.pack,在录制时可以作为 packFn 传入。inlineStylesheet: false,sampling: {scroll: 150, // 每 150ms 最多触发一次// set the interval of media interaction eventmedia: 800,// input: 'last' // 连续输入时,只录制最终值},})window.stopRecordFn = stopFn
}
  • 提交录制数据

因为一般提交页面录制数据的时机为页面离开的时机,当浏览器中的某个页面发生终止时,不能保证进程中的HTTP请求会成功(请参阅有关“终止”和页面生命周期的其他状态的更多信息)。所以我们有如下几个解决方法:

  1. 使用async/await阻塞异步请求,直至请求发送完毕再进行路由跳转,但似乎这种方法牺牲了用户体验;

  2. 使用fetch请求的keepalive标识进行数据提交,但是会有浏览器兼容性问题,其兼容性如下图:

  3. 使用Navigator.sendBeacon(),该函数专门用于发送单向请求(信标)。但是此 API 不允许您发送自定义标头。因此,为了让我们以“application/json”的形式发送数据,我们需要做一些小调整并使用Blob:

    /*** beacon上传可回溯录制数据*/
    export function saveTCDataByBeacon(data) {const url = `${RECORD_BASE_API}/tc/groOrder/saveTcData`// let data = new FormData();// for (let key in params) {//     data.append(key, params[key]);// }const headers = {type: 'application/json'}const blob = new Blob([JSON.stringify(data)], headers)return navigator.sendBeacon(url, blob)
    }
    

    但是注意:beacon只能提交少量数据,chrome限制最高64KB

基于上诉思路我们封装提交录制方法:

/**** @param stepIndex 录制节点 立即投保: 100, 暂存: 200, 提交审核: 300, 支付: 400, 支付成功: 500* @param goodsCode* @param submitType 提交数据的方式 默认xhr,页面返回beacon*/
export async function submitRecord(stepIndex, linkNo, submitType = 'xhr') {if (!window.screenRecords || !window.screenRecords.length) returnconst startEvent = unpack(window.screenRecords[0])const endEvent = unpack(window.screenRecords[window.screenRecords.length - 1])const { data: tcKey } = await getTcKey({ linkNo })const dataString = JSON.stringify(window.screenRecords)window.screenRecords.length = 0const params = {linkNo,tcKey,stepIndex,startTime: startEvent.timestamp,endTime: endEvent.timestamp,data: dataString,}// if (stepIndex >= 60) {//   params.linkNo = linkNo//   delete params.tcKey// }return new Promise((reslove, reject) => {// @ts-ignoreif (navigator && navigator.sendBeacon && submitType === 'beacon') {// beacon只能提交少量数据,chrome限制最高64KBconst result = saveTCDataByBeacon(params)if (result) {console.log('回溯数据请求成功排队 等待执行')reslove()} else {console.log('回溯数据提交失败')reject('回溯数据提交失败')}} else if (submitType === 'fetch') {saveTCDataByFetch(params).then(() => {reslove()}).catch(e => reject(e))} else {saveTCDataByXhr(params).then(() => {reslove()}).catch(e => reject(e))}})
}/*** xhr上传可回溯录制数据*/
export function saveTCDataByXhr(data) {return request({url: `${RECORD_BASE_API}/tc/groOrder/saveTcData`,method: 'post',data,})
}/*** Fetch上传可回溯录制数据 将 keepalive 设置为 true 就可确保浏览器关闭或回退,调用接口的链接不会被关闭,调用成功*/
export function saveTCDataByFetch(data) {const url = `${RECORD_BASE_API}/tc/groOrder/saveTcData`const headers = {'Content-Type': 'application/json;charset=UTF-8',[REQUEST_TOKEN_KEY]: getToken()}return new Promise((resolve, reject) => {fetch(url, {method: 'POST',headers,body: JSON.stringify(data),// keepalive: true,}).then(res => {resolve(res.json()) }).catch(error => {reject(error) })})
}
页面使用

开始录制:

startRecord()

提交录制数据:

submitRecord(300, this.baseInfo.grpLinkNo)

页面回放:

</template>    <!-- 回放容器 --><div ref="replayContainer" class="replay-container flex justify-center" />
</template><script setup>import { ref, onMounted} from 'vue';import RrwebPlayer from 'rrweb-player';import { unpack } from 'rrweb';const replayContainer = ref();const events = ref([]) // 回放数据通过服务端获取onMounted(() => {new RrwebPlayer({target: replayContainer.value,unpackFn: unpack,props: {events: events, // 包含回放所需的数据skipInactive: true, // 是否快速跳过无用户操作的阶段autoPlay: false, // 是否自动播放UNSAFE_replayCanvas: true, // 回放时是否回放 canvas 内容,开启后将会关闭沙盒策略,导致一定风险mouseTail: false, // 是否在回放时增加鼠标轨迹},})})})
</script>

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com