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

Why do modern JavaScript Frameworks discourage direct interaction with the DOM

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

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

如果有人只了解一个特定的框架,我会非常有兴趣阅读我的问题的答案,即使它不是一般化的。显然,我要再 google 这个问题,但我还没有在这里看到类似的问题,所以我想 post 是为了 post 。提前感谢您的任何见解!

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

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

  • 像 Angular 和 React 这样的现代框架旨在隐藏 DOM,因为它们想抽象掉 DOM。通过直接使用 DOM,您打破了抽象并使您的代码容易受到框架中引入的更改的影响。
  • 想要抽象掉 DOM 的原因有很多,链接到的 Reddit 页面主要关注 "state management",因为您的框架(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 的另一个原因是确保您的代码除了典型的网络浏览器 document/window DOM 环境,例如“server-side Angular”是一个东西,其中一些 Angular 代码在服务器上运行以预渲染 HTML 发送到客户端最小化应用程序启动延迟或允许没有 JavaScript 的网络浏览器访问您的网页,在这些情况下,正常的 W3C DOM 不再可用,但 "fake" 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 的回答非常好,我想补充一下。在大多数情况下,您不应直接操作 dom。在某些情况下您必须这样做,这是正确的做法。

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

有这种情况,需要访问dom。好的做法是将此类代码封装起来并使用框架方式访问某些内容,而不是伸手去拿 document/dom.