React 虚拟 DOM 的设计模式
1. 代理模式
引申:VUE2 与 VUE3 的响应式原理,最大区别就是 VUE3 采用了
Proxy
代理,而 VUE2 采用的是Object.defineProperty
。
核心思想:通过代理对象来间接操作真实对象,隐藏复杂实现细节。
javascript
class RealDOM {
render() {
console.log("Rendering the real DOM...");
}
}
class VirtualDOMProxy {
constructor() {
this.realDOM = new RealDOM();
}
render() {
console.log("Performing virtual DOM diff...");
this.realDOM.render();
}
}
const proxy = new VirtualDOMProxy();
proxy.render();
// Output:
// Performing virtual DOM diff...
// Rendering the real DOM...
2. 观察者模式
核心思想:虚拟 DOM 中状态变化会通知相关组件更新。
javascript
// 定义一个观察者类
class Observer {
constructor() {
// 初始化观察者对象时,创建一个空的订阅者数组
// 该数组用于存储所有订阅了这个观察者的回调函数(观察者模式的订阅者)
this.subscribers = [];
}
// 订阅方法,将传入的回调函数(订阅者)加入到订阅者数组中
subscribe(fn) {
// 将回调函数添加到订阅者列表
this.subscribers.push(fn);
}
// 通知方法,当状态发生变化时,调用所有订阅者的回调函数
notify(data) {
// 遍历所有订阅者,并调用他们的回调函数,传入新的状态数据
// 这里的 'data' 是状态数据,所有的订阅者都会得到这个数据更新
this.subscribers.forEach((fn) => fn(data));
}
}
// 创建一个观察者实例
const stateObserver = new Observer();
// 订阅:将一个回调函数添加到观察者的订阅者列表中
// 该回调函数会在通知方法调用时执行,接收状态数据并打印
stateObserver.subscribe((state) => console.log("State updated:", state));
// 模拟状态变化并通知所有订阅者
// 通过 notify 方法,状态更新时,会通知所有的订阅者,触发订阅者的回调
stateObserver.notify({ count: 1 });
3. 策略模式
核心思想:为虚拟 DOM 更新定义不同策略。
javascript
class UpdateStrategy {
static replace() {
console.log("Replacing the entire DOM node.");
}
static patch() {
console.log("Patching the updated parts of the DOM.");
}
}
function updateDOM(strategy = "patch") {
UpdateStrategy[strategy]();
}
updateDOM("replace"); // Output: Replacing the entire DOM node.
updateDOM("patch"); // Output: Patching the updated parts of the DOM.
4. 单例模式
核心思想:虚拟 DOM 全局只有一个实例。
javascript
class VirtualDOMSingleton {
constructor() {
if (!VirtualDOMSingleton.instance) {
this.tree = {};
VirtualDOMSingleton.instance = this;
}
return VirtualDOMSingleton.instance;
}
}
const dom1 = new VirtualDOMSingleton();
const dom2 = new VirtualDOMSingleton();
console.log(dom1 === dom2); // Output: true
5. 组合模式
核心思想:虚拟 DOM 的树状结构组织。
javascript
class VNode {
constructor(type) {
this.type = type;
this.children = [];
}
addChild(node) {
this.children.push(node);
}
render() {
console.log(`Rendering ${this.type}`);
this.children.forEach((child) => child.render());
}
}
const root = new VNode("div");
const child1 = new VNode("span");
const child2 = new VNode("button");
root.addChild(child1);
root.addChild(child2);
root.render();
// Output:
// Rendering div
// Rendering span
// Rendering button
6. 工厂模式
核心思想:为虚拟 DOM 提供统一创建方法。
javascript
class VNode {
constructor(type, props = {}) {
this.type = type;
this.props = props;
this.children = [];
}
}
class VNodeFactory {
static create(type, props, children = []) {
const node = new VNode(type, props);
node.children = children;
return node;
}
}
const vNode = VNodeFactory.create("div", { id: "app" }, [
VNodeFactory.create("h1", {}, ["Hello World"]),
]);
console.log(vNode);
7. 装饰器模式
核心思想:为虚拟 DOM 节点增强功能。
javascript
function withLogging(vNode) {
vNode.log = function () {
console.log(`VNode of type ${this.type}`);
};
return vNode;
}
let node = { type: "div" };
node = withLogging(node);
node.log(); // Output: VNode of type div
8. 命令模式
核心思想:将虚拟 DOM 的操作封装为命令。
javascript
class Command {
constructor(execute) {
this.execute = execute;
}
}
class DOMCommands {
static createElement(tag) {
return new Command(() => console.log(`Creating element: <${tag}>`));
}
static removeElement(tag) {
return new Command(() => console.log(`Removing element: <${tag}>`));
}
}
const createDiv = DOMCommands.createElement("div");
createDiv.execute();
9. 迭代器模式
核心思想:遍历虚拟 DOM 树结构。
javascript
class VNode {
constructor(type, children = []) {
this.type = type;
this.children = children;
}
*[Symbol.iterator]() {
yield this;
for (const child of this.children) {
yield* child;
}
}
}
const tree = new VNode("div", [
new VNode("h1"),
new VNode("p", [new VNode("span")]),
]);
for (const node of tree) {
console.log(node.type);
}
// Output:
// div
// h1
// p
// span
10. 享元模式
核心思想:复用相同的虚拟 DOM 节点。
javascript
class VNodeFactory {
static nodes = {};
static getNode(type) {
if (!this.nodes[type]) {
this.nodes[type] = new VNode(type);
}
return this.nodes[type];
}
}
const node1 = VNodeFactory.getNode("div");
const node2 = VNodeFactory.getNode("div");
console.log(node1 === node2); // Output: true
11. 原型模式
核心思想:通过克隆生成新的虚拟 DOM。
javascript
class VNode {
constructor(type, props) {
this.type = type;
this.props = props;
}
clone() {
return new VNode(this.type, { ...this.props });
}
}
const originalNode = new VNode("div", { id: "app" });
const clonedNode = originalNode.clone();
console.log(clonedNode); // Output: VNode { type: "div", props: { id: "app" } }
12. 适配器模式
核心思想:为虚拟 DOM 提供统一的接口,将不同结构或类型的输入转化为虚拟 DOM 可以识别的格式。
代码示例:
javascript
class JSONToVNodeAdapter {
static adapt(json) {
const { type, props, children } = json;
return new VNode(
type,
props,
children.map((child) => JSONToVNodeAdapter.adapt(child))
);
}
}
class VNode {
constructor(type, props = {}, children = []) {
this.type = type;
this.props = props;
this.children = children;
}
}
const jsonInput = {
type: "div",
props: { id: "app" },
children: [{ type: "h1", props: {}, children: ["Hello World"] }],
};
const adaptedVNode = JSONToVNodeAdapter.adapt(jsonInput);
console.log(adaptedVNode);
// Output: A VNode object tree.
13. 模板方法模式
核心思想:为虚拟 DOM 的渲染定义固定的流程,但允许子类重写某些步骤以定制行为。
代码示例:
javascript
class VirtualDOMRenderer {
render(vNode) {
this.beforeRender(vNode);
this.renderNode(vNode);
this.afterRender(vNode);
}
beforeRender(vNode) {
console.log("Preparing to render:", vNode.type);
}
renderNode(vNode) {
console.log("Rendering:", vNode.type);
vNode.children.forEach((child) => this.render(child));
}
afterRender(vNode) {
console.log("Finished rendering:", vNode.type);
}
}
class CustomRenderer extends VirtualDOMRenderer {
beforeRender(vNode) {
console.log("Custom logic before rendering:", vNode.type);
}
}
const renderer = new CustomRenderer();
const root = new VNode("div", {}, [new VNode("span"), new VNode("button")]);
renderer.render(root);
14. 中介者模式
核心思想:通过中介者协调虚拟 DOM 的不同部分,减少组件之间的直接依赖。
代码示例:
javascript
class DOMMediator {
constructor() {
this.components = [];
}
register(component) {
this.components.push(component);
component.setMediator(this);
}
notify(sender, event) {
console.log(`Mediator received ${event} from ${sender.type}`);
this.components.forEach((component) => {
if (component !== sender) component.receive(event);
});
}
}
class Component {
constructor(type) {
this.type = type;
this.mediator = null;
}
setMediator(mediator) {
this.mediator = mediator;
}
send(event) {
console.log(`${this.type} sends ${event}`);
this.mediator.notify(this, event);
}
receive(event) {
console.log(`${this.type} received ${event}`);
}
}
const mediator = new DOMMediator();
const div = new Component("div");
const span = new Component("span");
mediator.register(div);
mediator.register(span);
div.send("update");
// Output:
// div sends update
// Mediator received update from div
// span received update
15. 状态模式
核心思想:通过将虚拟 DOM 的状态分离,动态切换状态的行为。
代码示例:
javascript
class VNode {
constructor(type) {
this.type = type;
this.state = new DefaultState();
}
setState(state) {
this.state = state;
}
render() {
this.state.render(this);
}
}
class DefaultState {
render(vNode) {
console.log(`${vNode.type} rendered in default state.`);
}
}
class UpdatedState {
render(vNode) {
console.log(`${vNode.type} rendered in updated state.`);
}
}
const node = new VNode("div");
node.render(); // Default state
node.setState(new UpdatedState());
node.render(); // Updated state
16. 备忘录模式
核心思想:保存虚拟 DOM 的状态以便在需要时恢复。
代码示例:
javascript
class VNodeMemento {
constructor(state) {
this.state = state;
}
}
class VNode {
constructor(type, props) {
this.type = type;
this.props = props;
}
saveState() {
return new VNodeMemento({ ...this.props });
}
restoreState(memento) {
this.props = memento.state;
}
}
const node = new VNode("div", { id: "app" });
const memento = node.saveState();
node.props.id = "new-app";
console.log(node.props); // { id: "new-app" }
node.restoreState(memento);
console.log(node.props); // { id: "app" }
17. 访问者模式
核心思想:为虚拟 DOM 的每个节点提供操作扩展,而无需改变其定义。
代码示例:
javascript
class VNode {
constructor(type, children = []) {
this.type = type;
this.children = children;
}
accept(visitor) {
visitor.visit(this);
this.children.forEach((child) => child.accept(visitor));
}
}
class Renderer {
visit(node) {
console.log(`Rendering node: ${node.type}`);
}
}
const tree = new VNode("div", [new VNode("span"), new VNode("button")]);
const renderer = new Renderer();
tree.accept(renderer);
// Output:
// Rendering node: div
// Rendering node: span
// Rendering node: button
18. 解释器模式
核心思想:解析虚拟 DOM 节点语法并执行。
代码示例:
javascript
class Interpreter {
static interpret(vNode) {
if (typeof vNode === "string") {
return document.createTextNode(vNode);
}
const element = document.createElement(vNode.type);
for (const [key, value] of Object.entries(vNode.props || {})) {
element.setAttribute(key, value);
}
(vNode.children || []).forEach((child) =>
element.appendChild(Interpreter.interpret(child))
);
return element;
}
}
const virtualDOM = {
type: "div",
props: { id: "app" },
children: [
{ type: "h1", props: {}, children: ["Hello World"] },
{ type: "p", props: {}, children: ["This is a paragraph."] },
],
};
document.body.appendChild(Interpreter.interpret(virtualDOM));