为啥现代 JavaScript 框架不鼓励与 DOM 直接交互

Posted

技术标签:

【中文标题】为啥现代 JavaScript 框架不鼓励与 DOM 直接交互【英文标题】:Why do modern JavaScript Frameworks discourage direct interaction with the DOM为什么现代 JavaScript 框架不鼓励与 DOM 直接交互 【发布时间】:2019-04-01 08:32:14 【问题描述】:

在处理 AngularJS、Angular 和 React 等 JS 框架时,我观察到不鼓励直接与 DOM 交互,如果忽略警告,通常会导致错误。当我说“与 DOM 交互”时,我的意思是使用 document.getElementById('myElement') 和类似的方法来执行一些操作或从文档中读取值。

我的问题本质上是为什么?。这是一个虚拟 DOM 问题吗,其中 React(例如)没有跟踪实际 DOM,因此如果您“自行”进行更改而不通知 React 并随后更新虚拟 DOM,您会措手不及吗?在这种情况下,Angular 会不会有同样的问题?

如果有人只了解一个特定的框架,我会非常有兴趣阅读我的问题的答案,即使它不是一概而论的。显然,我要再去谷歌搜索一下,但我还没有在这里看到类似的问题,所以我想我会为后代发帖。提前感谢您提供任何见解!

【问题讨论】:

whats_so_wrong_with_direct_dom_manipulation ? 我不知道 Model-View-* 架构在这里有多相关,但本质上将 DOM 树视为视图 - 您不能直接从其外部的任何内容操作视图。 (鉴于这些框架抽象了视图本身,因此可以肯定地假设您也不编写任何自己的视图代码。) 【参考方案1】:

上面@Dai 的回答非常好,我想补充一下。在大多数情况下,您不应该直接操作 dom。在某些情况下,您必须这样做,这是正确的做法。

例如,React 和 Vue 都有 ref 的概念。它可以像一个 id 并让您访问 dom 节点。假设您正在构建一个聊天应用程序,当用户滚动到顶部时,您会在其中获取旧的聊天内容,并且您需要将最后一个可见的聊天内容保持在焦点上。

这种情况是存在的,我们需要访问dom。好的做法是将此类代码封装起来,并使用框架方式来访问某些内容,而不是访问文档/dom。

【讨论】:

【参考方案2】:

@HDJEMAI 链接到我将重复的这篇文章,因为这是一个很好的建议:https://www.reddit.com/r/javascript/comments/6btma7/whats_so_wrong_with_direct_dom_manipulation/

我将在下面详细说明其中的一些原因:

Angular 和 React 等现代框架旨在隐藏 DOM,因为它们希望将 DOM 抽象掉。通过直接使用 DOM,您打破了抽象并使您的代码对框架中引入的更改变得脆弱。

想要抽象出 DOM 的原因有很多,链接到的 Reddit 页面主要关注“状态管理”,因为您的框架(Angular、React 等)可能会对 DOM 的状态做出假设如果你直接操作 DOM 会被破坏,例如:

function this_is_your_code() 

    tell_angular_to_make_my_sidebar_500px_wide();

    document.getElementById('mysidebar').style.width = 700px;

    var sidebar_width = ask_angular_for_sidebar_width();
    console.log( sidebar_width ); // will print "500px"

抽象掉 DOM 的另一个原因是确保您的代码可以在典型的 Web 浏览器 document/window DOM 环境之外使用非传统 DOM,例如“server-side Angular”是一个东西,其中一些Angular 代码在服务器上运行以预渲染 html 以发送到客户端以最小化应用程序启动延迟或允许没有 JavaScript 的网络浏览器访问您的网页,在这些情况下,普通的 W3C DOM 不再可用,但是一个“假”的 DOM 是可用的,但它是由 Angular 提供的——它只能通过 Angular 的抽象来工作——如果你直接操作 document 它将不起作用,例如:

function this_is_your_code_that_runs_in_nodejs() 

    tell_angular_to_make_my_sidebar_500px_wide(); // this works and Angular's built-in abstraction of the DOM makes the appropriate change to the rendered server-side HTML

    document.getElementById('mysidebar').style.width = 500px; // fails because `document` is not available

【讨论】:

感谢@Dai 的详细回答,并感谢您提供有用的 Reddit 线程。这一切都非常有趣和有见地。

以上是关于为啥现代 JavaScript 框架不鼓励与 DOM 直接交互的主要内容,如果未能解决你的问题,请参考以下文章

不鼓励对 JavaScript 原生类型进行原型设计?

为啥不鼓励使用单例模式? [复制]

为啥不鼓励按钮导航?

为啥在休眠中不鼓励复合键?

为啥不鼓励在 Java EE 容器中生成线程?

译向恐龙解释现代JavaScript