😏 别再背面经啦,一文告诉你为啥要有虚拟DOM😍

153 阅读4分钟

别再背面经啦,一文告诉你为啥要有虚拟DOM


一、面经里的说法为啥不够好?😖


面经里说可能会说,是因为虚拟Dom能提高效率。它说的对吗?😶对也不对,因为,虚拟Dom能提高效率不是和真实DOM比,直接操作真实DOM绝对效率更高,这里的效率更高是自身前后对比不是和真实DOM比。 React和Vue的最小组成单位还是太大了,Vue组件内发生变化,这个组件的所有的DOM都要发生改变。 而react的最小组成单位一个基本都是一个页面了,需要操作的真实Dom更多。 于是它们都搞了就有了虚拟DOM来优化效率;当要渲染的数据发生变化,就把这次的变化存到js对象的虚拟DOM里并和之前的一次存的虚拟DOM比较,只改变找的变动的虚拟Dom节点。 然后改变这些找到变动的虚拟DOM节点对应的真实DOM然后改变它。 这样说面经里的那句话才完整,意义才明晰。😋


二、为啥原生DOM操作一定比虚拟DOM快?😐


首先原生js操作Dom直接可以通过document.getElementById()直接改变。

像Vue和React生成的虚拟DOM还要前后对比,用diff,picth算法这些都是会耗费性能的,甚至最后不一定能找准真实DOM节点,可 能会找出比实际需要更多的DOM节点。所以一定比原生DOM慢。


三、为啥要有虚拟DOM?😪


一、Vue和React是为了实现数据驱动而生的框架💩


其实如果我们没有动态的数据,只有简单的页面和event(早期切图崽生存环境,据说当年做后端的也做切图),我们完全可以通 过html、css库和js来快速开发。但是呢,后来因为要变化的数据越来越多,就有了Vue和React框架来加速开发。

举个例子如果我们要渲染一个这样的表格。

image-20250604010029026.png

包含以下数据

    const friends = [
            {
             name: "李宏伟",
              hometown:"京海莽村"
            },
            {
              name:"高启强",
              hometown:"京海旧厂街"
            },
            {
              name:"安欣",
              hometown:"京海旧厂街"
            }
          ]
         // 知道我是谁了吧,这些人都是我的好朋友。💪💪💪💪💪💪💪💪💪💪💪

让我们看看原生js,vue,和React的实现区别:

原生js写法😏

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>原生js</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4Q6Gf2aSP4eDXB8Miphtr37CMZZQ5oXLH2yaXMJ2w8e2ZtHTl7GptT4jmndRuHDT" crossorigin="anonymous">
</head>
<body>
  <div class="container">
    <!-- 挂载点 -->
   <table id="friends" class="table table-striped">
    <thead>
      <tr>
        <th>姓名</th>
        <th>家乡</th>
      </tr>
    </thead>
      <tbody>
      <tr>
        <td>李宏伟</td>
        <td>抚州</td>
      </tr>
   </table>
  </div>
  <script>
    const oBody = document.querySelector('#friends tbody'); // 能不能找到挂载点后的事情交给框架去做
    const friends = [
            {
             name: "李宏伟",
              hometown:"京海莽村"
            },
            {
              name:"高启强",
              hometown:"京海旧厂街"
            },
            {
              name:"安欣",
              hometown:"京海旧厂街"
            }
          ]
    oBody.innerHTML = friends.map(item=>
       `
      <tr>
      <td>${item.name}  </td>
      <td>${item.hometown}</td>
      </tr>
      `
    ).join('');
    // map返回的是一个数组,如果不用join,这里用加法会蕴含默认的数组对象转化成字符串 ""+[1,2,3] = '1,2,3',默认用逗号分隔,自动调用toString方法。
    // 所以这里用join('') 把数组转化成字符串。
    
​
  </script>
</body>
</html>

我们可以看到我们是通过字符串拼接来讲数据放入html页面中,讲真我感觉比react好写(主要是以前可能没有模板字符串,要不然感觉很多框架没必要😅)。

ok再来看看vue2怎么写的:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>用js框架</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4Q6Gf2aSP4eDXB8Miphtr37CMZZQ5oXLH2yaXMJ2w8e2ZtHTl7GptT4jmndRuHDT" crossorigin="anonymous">
</head>
<body>
  <div class="container" id = "app">
    <!-- 挂载点 -->
    
   <table id="friends" class="table table-striped">
    <thead>
      <tr>
        <th>姓名</th>
        <th>家乡</th>
      </tr>
    </thead>
    <!-- <tbody>//挂载点就是tbody的可变部分 -->
      <tbody>
      <tr>
        <tr v-for = "friend in friends">
          <td>{{friend.name}}</td>
          <td>{{friend.hometown}}</td>
        </tr>
      </tr>
    </tbody>
    <tfoot>
    </tfoot>
   </table>
  </div>
  <!-- // js应该放到body尾部,因为dom加载完了才能执行js,而且可以让界面先加载。 -->
  <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/3.2.31/vue.global.min.js"></script>
  <script>
    //起手就是一个App
    const App = {
      // 声明数据的业务
      data(){
        return {
​
          friends:[
            {
             name: "李宏伟",
              hometown:"京海莽村"
            },
            {
              name:"高启强",
              hometown:"京海旧厂街"
            },
            {
              name:"安欣",
              hometown:"京海旧厂街"
            }
          ]
        }
      }
    }
    // 把App 变成一个vue实例,挂载到id为friends的元素上。
    Vue.createApp(App).mount('#app');// 选择id = app 的元素及其后代元素都可以访问到data中的数据。
​
  </script>
</body>
</html>

可以看到vue2还是兼容性比较好的,可以访问CDN简单的重构代码。

接着我们再来看看React写法:

// index.html 
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <!-- 添加 Bootstrap CSS CDN -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + React + TS</title>
  </head>
  <body>
    <div id="root"></div>
    <!-- 添加 Bootstrap JS CDN -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
    <script type="module" src="/src/main.tsx"></script>
  </body>
</html>

这里也能发现要使用bootstrap,要把link标签写在index.html里,App.jsx就可以顺利访问了。

//App.jsx
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'function App() {
  const [firends, setFirends] = useState(
    [
      {
       name: "李宏伟",
        hometown:"京海莽村"
      },
      {
        name:"高启强",
        hometown:"京海旧厂街"
      },
      {
        name:"安欣",
        hometown:"京海旧厂街"
      }
    ]
  )
​
  return (
    <>
     <table className="table table-striped table-hover">
      <thead className="table-dark">
        <tr>
          <th>姓名</th>
          <th>家乡</th>
        </tr>
      </thead>
      <tbody>
        {
          firends.map((item,index) => (
            <tr key={index}>
              <td className="text-start">{item.name}</td>
              <td className="text-info">{item.hometown}</td>
            </tr>
          ))
        }
      </tbody>
     </table>
    </>
  )
}
​
export default App

实话实说,感觉不出React哪里比原生nb。😂


小总结👊

这些框架其实大同小异,目的都是设计了一套可以在html里直接访问到数据的方法,vue2是用 {{变量名}}来访问,React用{变量名}

访问,还有的像我在学校学的超老jsp技术的目的就是用<%····java代码·····%>来实现写出交互效果。


二、跨端解耦,不把代码和真实DOM绑死👈


另外虚拟dom的好处就是实现一次编写多端互用,不把代码和真实代码绑定死,让同一个代码可以多端互用,原理也不难理解。

大概是把原来虚拟dom和web的真实dom的映射改为对移动端相关节点的映射就好了👴。

既然看到这里了可不可以给我点一个赞😉,虽然写的是💩。