【问题标题】:React: How much can I manipulate the DOM React has rendered?React:我可以对 React 渲染的 DOM 进行多少操作?
【发布时间】:2014-06-25 04:37:39
【问题描述】:

这就是我正在做的事情:jsfiddle

关键部分是:

position: function() {
  var container = $(this.getDOMNode());
  this._menu = $(this.refs.menu.getDOMNode());
  this._menu.appendTo(document.body).
      offset({
          top: container.offset().top + 
              container.outerHeight(),
          left: container.offset().left
      });
},
restore: function() {
  this._menu.appendTo(this.getDOMNode());      
},
componentWillUpdate: function() {
  this.restore();
},
componentDidUpdate: function() {
  this.position();
},
componentDidMount: function() {
  this.position();
},

现在效果很好。我在组件更新之前将内容放回去,假设 React 在更新之间单独保留 DOM 并且不会错过它。事实上,React 似乎可以很好地移动内容(如果我删除 componentWillUpdatecomponentDidUpdate,定位的元素仍然会更新!)

我的问题是有多少由此产生的假设是安全的(即,如果我假设这些事情,我的代码会在未来版本的 React 中中断吗?):

  • React 不关心 DOM 是否在更新之间移动,只要您将其放回 componentWillUpdate
  • React 事件处理程序仍将处理已移动的元素。
  • React 会将您要求的任何内联样式与元素上已有的样式合并(即使它没有设置它们。)
  • React 将更新它已渲染的 DOM,即使您将该 DOM 移动到文档中的其他位置!

最后一个对我来说似乎有些极端和神奇,但如果它成立,就会产生一些重大影响。

【问题讨论】:

  • 我真的很喜欢这个问题。它会询问我想要的所有东西以及更多。好东西!
  • 您可以查看 react-bootstrap 如何实现似乎不受滚动区域影响的工具提示。我认为它会创建一个新的 div 并附加到正文,然后为该 div 渲染一个新的根,其中只有工具提示。这样,工具提示可以绝对定位在页面上的任何位置。

标签: dom reactjs


【解决方案1】:

我是一名 React 开发人员。我会回答你的每一个问题:


只要将 DOM 放回 componentWillUpdate 中,React 并不关心 DOM 是否在更新之间移动。

True -- React 不查看 DOM,除非在更新时,事件处理程序除外:

React 事件处理程序仍将处理已移动的元素。

我不会依赖这个,我现在甚至不确定它是不是真的。

React 会将您要求的任何内联样式与元素上已有的样式合并(即使它没有设置它们。)

我也不会依赖这个——现在 React 设置了单独的属性,但我可以很容易地想象它设置 el.style.cssText 如果这样更快,那会吹掉你所做的个别更改。

React 会更新它渲染的 DOM,即使你将 DOM 移动到文档中的其他位置!

目前我不相信这是真的,你也不应该依赖这个。


一般来说,您不应该手动操作 React 创建的 DOM。在 React 中创建一个空的 <div> 并手动填充它是 100% 洁净的;甚至可以修改 React 渲染元素的属性,只要您以后不尝试在 React 中更改其属性(导致 React 执行 DOM 更新),但是如果您移动一个元素,React 可能会查找它并找不到时会感到困惑。

希望对您有所帮助。

【讨论】:

  • 谢谢!很有启发性。
  • 那么您将如何解决我的问题?例如,滚动区域内的下拉菜单被溢出切断......我总是将元素移动到正文,但似乎这不是 React 方式。
  • "React 会更新它渲染的 DOM,即使你把那个 DOM 移到文档的其他地方!"如果 DOM 位于 React 根目录中,这似乎是正确的。我猜是实施的运气。
  • @Ben Alpert,我可以请您在这里查看一个与反应相关的问题:stackoverflow.com/questions/27913004/…
  • 太棒了,这太棒了,我最终选择了 componentWillUpdate/componentDidUpdate(移动节点)。但是,如果我需要大量更新状态,我将不得不中断并仅依靠 componentDidMount/componentWillUnmount 来进行清理。
【解决方案2】:

一方面,我同意 Sophie 的观点,即您不应该根据实施细节做出决定。但是,我想说看看 React 是如何工作的仍然很有趣:

有些事情可能发生了一些变化,但通常情况就是这样,它是如何发生的。

  1. 考虑一下这样一个事实,即 React 在它创建的每个 DOM 元素上都放置了唯一的 id(现在是数据属性)。这些 ID 目前基于一个非常简单的系统。这应该解释系统 - 根节点总是'.0'

               .0
        .0.0        .0.1
    .0.0.0     .0.1.0 .0.1.1
    

每当您提供“键”属性时,您提供的值将用于 id 而不是列表中的索引,但系统保持不变。

  1. React 创建的 Virtual DOM 也有具有相同 id 的轻量级对象。这是虚拟 DOM 和真实 DOM 之间的简单映射系统。

  2. 这也是为什么如果您不提供 'key' 属性会覆盖列表中的元素,因为如果在列表中间添加或删除元素,则元素的 id 会发生变化。

牢记这一点:

只要将 DOM 放回 componentWillUpdate 中,React 并不关心 DOM 是否在更新之间移动。

是的。我认为即使您没有在更新之前将元素放回原处,事情也可能会起作用,因为 React 使用 ids 工作。但这将是一个非常棘手且不可靠的工作,因为可能会添加或删除元素并且可能会破坏。

React 事件处理程序仍将处理已移动的元素。

是的……在一定程度上。 react 中事件处理程序的工作方式是所有事件都是合成的。这意味着在 React 根 DOM 节点上只有一个事件监听器。在那里捕获的所有事件都与 React 中的事件侦听器匹配。我认为这也使用 ID 来匹配元素。然而,React 可能会对它的父元素做一些最小的检查。我认为只要元素保持在 React 渲染的同一个根节点内,这应该可以工作。也就是说,React 将来可能会更新 id 系统并在将来对父节点进行更多检查,这可能会中断。

React 会将您要求的任何内联样式与元素上已有的样式合并(即使它没有设置它们。)

这个问题已经回答了。目前有效,未来可能无效。我不认为它会在短期内改变,因为有一些动画系统依赖于这个实现细节。

React 会更新它渲染的 DOM,即使你把那个 DOM 移到文档的其他地方!

是的,如果您使用相同的 react-id 保留相同的 DOM 元素,react 将不会知道它已经在文档中移动,并且只会更新它,就好像它在它呈现它的相同位置一样。正如你已经注意到它需要在同一个 React Root 中。这很重要,因为 React 仅绑定到 React 根 DOM 节点以进行合成事件等。这样 React 可以与其他库很好地配合,并且不需要访问文档根目录。

注意事项:仅仅因为您可以做某事并不意味着您应该做某事。一般来说,你应该只添加额外的 DOM 节点,并在不由 React 管理的 DOM 节点上添加属性(样式:变换值在动画中很常见)。当您做其他事情时,请了解事情可能会奏效,但通常有更好的方法来做事情。


至于你的问题:

那么您将如何解决我的问题?例如,滚动区域内的下拉菜单被溢出切断......我总是将元素移动到正文,但似乎这不是 React 方式。

我认为这里的理想情况是一开始就将下拉菜单放在正文中。然后您可以在点击事件和下拉菜单之间传递消息。 您可以使用回调在虚拟 DOM 上足够高,然后将 props 一直更新到下拉列表以管理其状态。或者只使用一个好的事件系统。

【讨论】:

    猜你喜欢
    • 2020-03-30
    • 2022-07-04
    • 1970-01-01
    • 1970-01-01
    • 2020-10-03
    • 2018-05-20
    • 2021-11-06
    • 2021-03-26
    • 2020-11-04
    相关资源
    最近更新 更多