加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

web页面录屏实现

发布时间:2020-05-11 04:23:42 所属栏目:编程 来源:站长网
导读:副标题#e# 在看到评论后,突然意识到自己没有提前说明,本文可以说是一篇调研学习文,是我自己感觉可行的一套方案,后续会去读读已经开源的一些类似的代码库,补足自己遗漏的一些细节,所以大家可以当作学习文,生产环境慎用。 录屏重现错误场景 如果你的应

const options = { childList: true, // 是否观察子节点的变动 subtree: true, // 是否观察所有后代节点的变动 attributes: true, // 是否观察属性的变动 attributeOldValue: true, // 是否观察属性的变动的旧值 characterData: true, // 是否节点内容或节点文本的变动 characterDataOldValue: true, // 是否节点内容或节点文本的变动的旧值 // attributeFilter: ['class', 'src'] 不在此数组中的属性变化时将被忽略 }; const observer = new MutationObserver((mutationList) => { // mutationList: array of mutation }); observer.observe(document.documentElement, options);

使用起来很简单,你只需要指定一个根节点和需要监控的一些选项,那么当DOM变化时,在callback函数中就会有一个mutationList,这是一个DOM的变化列表,其中mutation的结构大概为:

{ type: 'childList', // or characterData、attributes target: <DOM>, // other params }

我们使用一个数组来存放mutation,具体的callback为:

const onMutationChange = (mutationsList) => { const getFlowId = (node) => { if (node) { // 新插入的DOM没有标记,所以这里需要兼容 if (!node.__flow) node.__flow = { id: uuid() }; return node.__flow.id; } }; mutationsList.forEach((mutation) => { const { target, type, attributeName } = mutation; const record = { type, target: getFlowId(target), }; switch (type) { case 'characterData': record.value = target.nodeValue; break; case 'attributes': record.attributeName = attributeName; record.attributeValue = target.getAttribute(attributeName); break; case 'childList': record.removedNodes = [...mutation.removedNodes].map(n => getFlowId(n)); record.addedNodes = [...mutation.addedNodes].map((n) => { const snapshot = this.takeSnapshot(n); return { ...snapshot, nextSibling: getFlowId(n.nextSibling), previousSibling: getFlowId(n.previousSibling) }; }); break; } this.records.push(record); }); } function takeSnapshot(node, options = {}) { this.markNodes(node); const snapshot = { vdom: createVirtualDom(node), }; if (options.doctype === true) { snapshot.doctype = document.doctype.name; snapshot.clientWidth = document.body.clientWidth; snapshot.clientHeight = document.body.clientHeight; } return snapshot; }

这里面只需要注意,当你处理新增DOM的时候,你需要一次增量的快照,这里仍然使用Virtual DOM来记录,在后面播放的时候,仍然生成DOM,插入到父元素即可,所以这里需要参照DOM,也就是兄弟节点。

表单元素监控

上面的MutationObserver并不能监控到input等元素的值变化,所以我们需要对表单元素的值进行特殊处理。

oninput事件监听

MDN文档: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/oninput

事件对象:select、input,textarea

window.addEventListener('input', this.onFormInput, true); onFormInput = (event) => { const target = event.target; if ( target && target.__flow && ['select', 'textarea', 'input'].includes(target.tagName.toLowerCase()) ) { this.records.push({ type: 'input', target: target.__flow.id, value: target.value, }); } }

在window上使用捕获来捕获事件,后面也是这样处理的,这样做的原因是我们是可能并经常在冒泡阶段阻止冒泡来实现一些功能,所以使用捕获可以减少事件丢失,另外,像scroll事件是不会冒泡的,必须使用捕获。

onchange事件监听

MDN文档: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/oninput

input事件没法满足type为checkbox和radio的监控,所以需要借助onchange事件来监控

window.addEventListener('change', this.onFormChange, true); onFormChange = (event) => { const target = event.target; if (target && target.__flow) { if ( target.tagName.toLowerCase() === 'input' && ['checkbox', 'radio'].includes(target.getAttribute('type')) ) { this.records.push({ type: 'checked', target: target.__flow.id, checked: target.checked, }); } } }

onfocus事件监听

MDN文档: https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onfocus

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读