> For the complete documentation index, see [llms.txt](https://coffe1891.gitbook.io/frontend-hard-mode-interview/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://coffe1891.gitbook.io/frontend-hard-mode-interview/id-1/4.-liu-lan-qi-v8-yin-qing/1.4.3.md).

# 壹.4.3 DOM、Shadow DOM、Virtual DOM

在前端开发中，DOM（Document Object Model）是一个核心概念，而Shadow DOM和Virtual DOM则是现代前端框架中的重要技术。本文将详细介绍这三者的概念、区别和应用场景。

## 壹.4.3.1 DOM（Document Object Model）

### 什么是DOM

DOM是HTML文档的编程接口，它将HTML文档表示为一个树形结构，每个HTML元素都是树中的一个节点。DOM提供了操作HTML元素的方法和属性，让JavaScript能够动态地修改网页内容。

### DOM树结构

```html
<!DOCTYPE html>
<html>
  <head>
    <title>页面标题</title>
  </head>
  <body>
    <div id="container">
      <h1>标题</h1>
      <p>段落内容</p>
    </div>
  </body>
</html>
```

对应的DOM树结构：

```
document
├── html
    ├── head
    │   └── title
    └── body
        └── div#container
            ├── h1
            └── p
```

### DOM操作示例

```javascript
// 获取元素
const container = document.getElementById('container');
const title = document.querySelector('h1');

// 修改内容
title.textContent = '新标题';

// 创建新元素
const newParagraph = document.createElement('p');
newParagraph.textContent = '新段落';
container.appendChild(newParagraph);

// 删除元素
const oldParagraph = document.querySelector('p');
container.removeChild(oldParagraph);
```

### DOM的优缺点

**优点：**

* 标准化的API，浏览器原生支持
* 直接操作真实DOM，响应及时
* 丰富的操作方法和属性

**缺点：**

* 操作频繁时性能较差
* 容易产生内存泄漏
* 跨浏览器兼容性问题

## 壹.4.3.2 Shadow DOM

### 什么是Shadow DOM

Shadow DOM是Web Components标准的一部分，它允许开发者创建封装的DOM树，这些DOM树与主文档的DOM树分离，具有自己的作用域。Shadow DOM主要用于创建可重用的Web组件。

### Shadow DOM的基本概念

```javascript
// 创建Shadow DOM
const host = document.getElementById('host');
const shadow = host.attachShadow({ mode: 'open' });

// 在Shadow DOM中添加内容
shadow.innerHTML = `
  <style>
    .shadow-text {
      color: red;
      font-size: 18px;
    }
  </style>
  <div class="shadow-text">这是Shadow DOM中的内容</div>
`;
```

### Shadow DOM的特点

1. **封装性**：Shadow DOM中的样式和脚本不会影响外部文档
2. **作用域隔离**：CSS选择器无法穿透Shadow DOM边界
3. **可重用性**：可以创建完全独立的组件

### 实际应用示例

```javascript
class CustomButton extends HTMLElement {
  constructor() {
    super();
    
    // 创建Shadow DOM
    const shadow = this.attachShadow({ mode: 'open' });
    
    // 添加样式和内容
    shadow.innerHTML = `
      <style>
        button {
          background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
          border: none;
          border-radius: 25px;
          color: white;
          cursor: pointer;
          font-size: 16px;
          padding: 12px 24px;
          transition: transform 0.2s;
        }
        
        button:hover {
          transform: scale(1.05);
        }
      </style>
      <button>
        <slot></slot>
      </button>
    `;
  }
}

// 注册自定义元素
customElements.define('custom-button', CustomButton);
```

使用方式：

```html
<custom-button>点击我</custom-button>
```

## 壹.4.3.3 Virtual DOM

### 什么是Virtual DOM

Virtual DOM是一个轻量级的JavaScript对象，它是对真实DOM的抽象表示。Virtual DOM的主要目的是提高DOM操作的性能，通过比较虚拟DOM的差异，批量更新真实DOM。

### Virtual DOM的工作原理

1. **创建虚拟DOM**：将真实DOM转换为JavaScript对象
2. **状态变化**：当数据发生变化时，创建新的虚拟DOM
3. **差异比较**：比较新旧虚拟DOM的差异
4. **批量更新**：将差异应用到真实DOM

### 简单的Virtual DOM实现

```javascript
// 创建虚拟DOM元素
function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === 'string' ? createTextElement(child) : child
      )
    }
  };
}

function createTextElement(text) {
  return {
    type: 'TEXT_ELEMENT',
    props: {
      nodeValue: text,
      children: []
    }
  };
}

// 渲染虚拟DOM到真实DOM
function render(element, container) {
  const dom = element.type === 'TEXT_ELEMENT'
    ? document.createTextNode('')
    : document.createElement(element.type);
  
  // 设置属性
  Object.keys(element.props)
    .filter(key => key !== 'children')
    .forEach(name => {
      dom[name] = element.props[name];
    });
  
  // 递归渲染子元素
  element.props.children.forEach(child => render(child, dom));
  
  container.appendChild(dom);
}

// 使用示例
const element = createElement(
  'div',
  { id: 'app' },
  createElement('h1', null, 'Hello Virtual DOM'),
  createElement('p', null, '这是一个简单的实现')
);

render(element, document.getElementById('root'));
```

### Virtual DOM的优势

1. **性能提升**：批量更新DOM，减少重排重绘
2. **跨平台**：虚拟DOM可以渲染到不同平台
3. **开发体验**：声明式编程，关注数据而非DOM操作
4. **状态管理**：更容易管理应用状态

### Virtual DOM的缺点

1. **内存占用**：需要额外的内存存储虚拟DOM
2. **首次渲染**：需要先创建虚拟DOM，再渲染到真实DOM
3. **学习成本**：需要理解虚拟DOM的概念和工作原理

## 壹.4.3.4 三者的关系与区别

### 关系图

```
真实DOM ←→ Virtual DOM ←→ 应用状态
    ↑
Shadow DOM (封装组件)
```

### 主要区别

| 特性   | DOM            | Shadow DOM     | Virtual DOM |
| ---- | -------------- | -------------- | ----------- |
| 作用   | 操作真实DOM        | 创建封装组件         | 提高渲染性能      |
| 性能   | 直接操作，性能较低      | 封装隔离，性能较好      | 批量更新，性能最佳   |
| 使用场景 | 原生JavaScript开发 | Web Components | 现代前端框架      |
| 复杂度  | 简单直接           | 中等             | 复杂          |

## 壹.4.3.5 实际应用建议

### 何时使用DOM

* 简单的页面交互
* 原生JavaScript项目
* 需要直接控制DOM的场景

### 何时使用Shadow DOM

* 创建可重用组件
* 需要样式封装
* 构建Web Components

### 何时使用Virtual DOM

* 复杂的前端应用
* 需要频繁更新DOM
* 使用现代前端框架

## 壹.4.3.6 结语

DOM、Shadow DOM和Virtual DOM各有其适用场景。理解它们的特点和区别，能够帮助我们在不同的项目中选择合适的技术方案。在实际开发中，这些技术往往是结合使用的，而不是相互排斥的。

### 推荐阅读

{% hint style="info" %}
[What is the Shadow DOM?](https://bitsofco.de/what-is-the-shadow-dom/)
{% endhint %}

{% hint style="info" %}
[Virtual DOM and Internals](https://reactjs.org/docs/faq-internals.html)
{% endhint %}

{% hint style="info" %}
[全面理解虚拟DOM，实现虚拟DOM](http://foio.github.io/virtual-dom/)
{% endhint %}
