首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >绕过React框架修改Dom元素

绕过React框架修改Dom元素

原创
作者头像
lealc
发布2024-12-27 20:06:48
发布2024-12-27 20:06:48
37700
代码可运行
举报
运行总次数:0
代码可运行

背景

最近碰到一个小难题,针对某个页面,提前植入js执行以填充某个Dom元素的值,例如需要填充某些表单便于用户进行一键提交。如果是原生的页面,使用element.value赋值就可以实现,比较简单,但是如果是框架实现的页面,例如React框架,就会遇到一个困难,就是你修改完了Dom元素的值再去触发了React框架重新渲染就会让React框架自身的state输出到Dom元素中,导致修改的值被回滚了。

打上断点就会发现回滚操作

回滚操作
回滚操作

实际上回滚的本质原因,就是因为没有同步修改React框架内保存的状态,导致不一致被React框架给回滚了。

那如何修改React框架内保存的状态呢?

解决

这里本质上,是需要解决React的state需要同步进行更改,如果只是修改Dom元素,就迟早会被React回滚回来。

解决前需要了解一下React框架的 _valueTracker 是什么

_valueTracker

_valueTracker 是 React 内部用于跟踪和管理表单元素(如 <input><textarea> 等)值变化的一个对象。它是 React 早期版本(特别是 React 15 及之前版本)中实现受控组件(controlled components)的一种方式。

受控组件

在 React 中,受控组件是指其值由 React 组件的状态控制的表单元素。这意味着表单元素的当前值存储在组件的状态中,并且任何更改都必须通过更新状态来驱动。这种方式使得 React 可以完全控制表单元素的行为和渲染。

_valueTracker的作用

_valueTracker对象用于记录表单元素的当前值以及该值是否由用户直接输入引起。它主要有两个属性:

value:存储表单元素的当前值。

isMounted:表示组件是否已经挂载到 DOM 上。

React 使用 _valueTracker 来优化性能和确保状态的一致性。例如,当组件的状态更新时,React 可以检查 _valueTracker 来确定是否需要重新渲染表单元素。

_valueTracker的实现机制

初始化:

当一个受控组件被创建时,React 会在组件实例上初始化一个 _valueTracker 对象,并将其与表单元素的当前值关联起来。

值的变化检测:

当组件的状态更新时,React 会检查 _valueTracker 中存储的值与新的状态值是否一致。

如果不一致,React 会更新表单元素的 DOM 值,并触发相应的事件(如 input 事件)。

事件处理:

当用户直接在表单元素中输入内容时,React 会捕获这些事件,并更新 _valueTracker 中的值。

这种机制确保了 React 的状态始终与实际的 DOM 值保持同步。

性能优化:

_valueTracker 还用于优化性能。例如,当组件的状态更新时,React 可以检查 _valueTracker 来确定是否需要重新渲染表单元素。

如果 _valueTracker 中的值已经是最新的,React 可以避免不必要的 DOM 操作。

React 版本更新

从 React 16 开始,React 引入了更先进的合成事件系统和更优化的状态管理机制,_valueTracker 不再是必需的,并且逐渐被废弃。在 React 17 及更高版本中,_valueTracker 已经被移除,React 使用其他方式来跟踪和管理表单元素的值。

实际解决

了解完_valueTracker 可以知道,React17以下基本上是可以兼容的,所幸我们需要修改的页面正好是符合要求的版本,直接上解决的代码(内含注释)

代码语言:javascript
代码运行次数:0
运行
复制
function changeReactInputValue(inputDom, newText) {
    let lastValue = inputDom.value; // 1. 获取输入框的当前值
    inputDom.value = newText; // 2. 将输入框的值设置为新的文本
    let event = new Event('input', { bubbles: true }); // 3. 创建一个新的 'input' 事件,并允许事件冒泡
    event.simulated = true; // 4. 标记事件为模拟事件(非用户真实操作)
    let tracker = inputDom._valueTracker; // 5. 访问React内部用于跟踪输入值的 _valueTracker 对象
    if (tracker) { // 6. 如果存在 _valueTracker 对象
        tracker.setValue(lastValue); // 7. 更新 _valueTracker 中的值,以保持React内部状态的一致性
    }
    inputDom.dispatchEvent(event); // 8. 触发 'input' 事件,通知React值已发生变化
}

// eg.
changeReactInputValue(document.getElementsByName("${className}")[0], "123123")

通过直接操作DOM来更改React管理的输入框的值,并通过手动触发事件和操作React的内部跟踪机制,确保React的状态与DOM保持同步。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 解决
    • _valueTracker
      • 受控组件
      • _valueTracker的作用
      • _valueTracker的实现机制
      • React 版本更新
    • 实际解决
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档