0
# Virtual DOM & Rendering
1
2
Vue's Virtual DOM system provides efficient DOM manipulation through virtual node abstractions and custom renderer support for targeting different platforms.
3
4
## Capabilities
5
6
### VNode Creation
7
8
Create virtual nodes representing DOM elements, components, and text.
9
10
```typescript { .api }
11
/**
12
* Creates a virtual node (shorthand function)
13
* @param type - Element tag, component, or special type
14
* @param props - Properties and attributes
15
* @param children - Child nodes or text content
16
* @returns Virtual node
17
*/
18
function h(type: string | Component, props?: VNodeProps | null, children?: VNodeArrayChildren): VNode;
19
function h(type: string | Component, children?: VNodeArrayChildren): VNode;
20
21
/**
22
* Creates a virtual node (full function)
23
* @param type - Node type (string, component, Symbol)
24
* @param props - Node properties and attributes
25
* @param children - Child nodes
26
* @param patchFlag - Optimization hint for diffing
27
* @param dynamicProps - Dynamic property names
28
* @returns Virtual node
29
*/
30
function createVNode(
31
type: VNodeTypes,
32
props?: VNodeProps | null,
33
children?: VNodeArrayChildren,
34
patchFlag?: number,
35
dynamicProps?: string[] | null
36
): VNode;
37
38
/**
39
* Clones a virtual node with optional additional props
40
* @param vnode - VNode to clone
41
* @param extraProps - Additional properties to merge
42
* @param mergeRef - Whether to merge refs
43
* @returns Cloned VNode
44
*/
45
function cloneVNode<T, U>(
46
vnode: VNode,
47
extraProps?: (T & VNodeProps) | null,
48
mergeRef?: boolean
49
): VNode;
50
51
/**
52
* Checks if a value is a VNode
53
* @param value - Value to check
54
* @returns True if value is a VNode
55
*/
56
function isVNode(value: unknown): value is VNode;
57
58
/**
59
* Merges multiple props objects into one
60
* @param args - Props objects to merge
61
* @returns Merged props object
62
*/
63
function mergeProps(...args: (VNodeProps | undefined)[]): VNodeProps;
64
```
65
66
**Usage Examples:**
67
68
```typescript
69
import { h, createVNode, cloneVNode, isVNode, defineComponent } from "@vue/runtime-core";
70
71
// Basic element creation with h()
72
const div = h('div', { class: 'container' }, 'Hello World');
73
74
// Element with multiple children
75
const header = h('header', [
76
h('h1', 'My App'),
77
h('nav', [
78
h('a', { href: '/home' }, 'Home'),
79
h('a', { href: '/about' }, 'About')
80
])
81
]);
82
83
// Component usage
84
const MyComponent = defineComponent({
85
props: { message: String },
86
render() {
87
return h('p', this.message);
88
}
89
});
90
91
const componentVNode = h(MyComponent, { message: 'Hello from component' });
92
93
// Using createVNode for more control
94
const customVNode = createVNode(
95
'button',
96
{
97
class: 'btn btn-primary',
98
onClick: () => console.log('clicked')
99
},
100
'Click me'
101
);
102
103
// Cloning VNodes
104
const originalBtn = h('button', { class: 'btn' }, 'Original');
105
const clonedBtn = cloneVNode(originalBtn, { class: 'btn btn-large' });
106
107
// Check if value is VNode
108
if (isVNode(div)) {
109
console.log('div is a VNode:', div.type); // 'div'
110
}
111
```
112
113
### VNode Types & Symbols
114
115
Special VNode types for different content types.
116
117
```typescript { .api }
118
/**
119
* Fragment symbol for multiple root elements
120
*/
121
const Fragment: unique symbol;
122
123
/**
124
* Text node symbol
125
*/
126
const Text: unique symbol;
127
128
/**
129
* Comment node symbol
130
*/
131
const Comment: unique symbol;
132
133
/**
134
* Static node symbol for hoisted content
135
*/
136
const Static: unique symbol;
137
```
138
139
**Usage Examples:**
140
141
```typescript
142
import { h, Fragment, Text, Comment, createVNode } from "@vue/runtime-core";
143
144
// Fragment for multiple root elements
145
const multipleRoots = h(Fragment, [
146
h('header', 'Header'),
147
h('main', 'Main content'),
148
h('footer', 'Footer')
149
]);
150
151
// Text node
152
const textNode = createVNode(Text, null, 'Plain text content');
153
154
// Comment node
155
const commentNode = createVNode(Comment, null, 'This is a comment');
156
157
// Using in render functions
158
const MyComponent = defineComponent({
159
render() {
160
return h(Fragment, [
161
h('h1', 'Title'),
162
h('p', 'Paragraph 1'),
163
h('p', 'Paragraph 2')
164
]);
165
}
166
});
167
```
168
169
### Custom Renderer Creation
170
171
Create custom renderers for different platforms or output targets.
172
173
```typescript { .api }
174
/**
175
* Creates a custom renderer with platform-specific operations
176
* @param options - Renderer configuration with platform operations
177
* @returns Renderer with render and createApp functions
178
*/
179
function createRenderer<
180
HostNode = RendererNode,
181
HostElement = RendererElement
182
>(options: RendererOptions<HostNode, HostElement>): Renderer<HostElement>;
183
184
/**
185
* Creates a custom hydration renderer for SSR
186
* @param options - Renderer configuration with hydration support
187
* @returns Hydration renderer
188
*/
189
function createHydrationRenderer<
190
HostNode = RendererNode,
191
HostElement = RendererElement
192
>(options: RendererOptions<HostNode, HostElement>): HydrationRenderer;
193
194
interface RendererOptions<HostNode = any, HostElement = any> {
195
// Node creation
196
createElement(type: string, namespace?: ElementNamespace): HostElement;
197
createText(text: string): HostNode;
198
createComment(text: string): HostNode;
199
200
// Node manipulation
201
insert(child: HostNode, parent: HostElement, anchor?: HostNode | null): void;
202
remove(child: HostNode): void;
203
204
// Content updates
205
setText(node: HostNode, text: string): void;
206
setElementText(node: HostElement, text: string): void;
207
208
// Property handling
209
patchProp(
210
el: HostElement,
211
key: string,
212
prevValue: any,
213
nextValue: any,
214
namespace?: ElementNamespace
215
): void;
216
217
// Tree traversal
218
parentNode(node: HostNode): HostElement | null;
219
nextSibling(node: HostNode): HostNode | null;
220
221
// Optional: namespace handling
222
querySelector?(selector: string): HostElement | null;
223
setScopeId?(el: HostElement, id: string): void;
224
cloneNode?(node: HostNode): HostNode;
225
insertStaticContent?(
226
content: string,
227
parent: HostElement,
228
anchor: HostNode | null,
229
namespace: ElementNamespace
230
): HostNode[];
231
}
232
```
233
234
**Usage Examples:**
235
236
```typescript
237
import { createRenderer, h } from "@vue/runtime-core";
238
239
// Canvas renderer example
240
interface CanvasNode {
241
type: string;
242
props: Record<string, any>;
243
children: CanvasNode[];
244
x?: number;
245
y?: number;
246
}
247
248
const canvasRenderer = createRenderer<CanvasNode, CanvasNode>({
249
createElement(type) {
250
return {
251
type,
252
props: {},
253
children: []
254
};
255
},
256
257
createText(text) {
258
return {
259
type: 'text',
260
props: { text },
261
children: []
262
};
263
},
264
265
createComment(text) {
266
return {
267
type: 'comment',
268
props: { text },
269
children: []
270
};
271
},
272
273
insert(child, parent, anchor) {
274
if (anchor) {
275
const index = parent.children.indexOf(anchor);
276
parent.children.splice(index, 0, child);
277
} else {
278
parent.children.push(child);
279
}
280
},
281
282
remove(child) {
283
// Implementation for removing from canvas
284
},
285
286
setText(node, text) {
287
if (node.type === 'text') {
288
node.props.text = text;
289
}
290
},
291
292
setElementText(node, text) {
293
node.children = [{
294
type: 'text',
295
props: { text },
296
children: []
297
}];
298
},
299
300
patchProp(el, key, prevValue, nextValue) {
301
el.props[key] = nextValue;
302
},
303
304
parentNode(node) {
305
// Return parent node
306
return null;
307
},
308
309
nextSibling(node) {
310
// Return next sibling
311
return null;
312
}
313
});
314
315
// Use the custom renderer
316
const { render, createApp } = canvasRenderer;
317
318
const canvasApp = createApp({
319
render() {
320
return h('rect', {
321
x: 10,
322
y: 10,
323
width: 100,
324
height: 50,
325
fill: 'blue'
326
});
327
}
328
});
329
```
330
331
### Low-level VNode Manipulation
332
333
Advanced VNode creation and manipulation functions.
334
335
```typescript { .api }
336
/**
337
* Creates a text VNode
338
* @param text - Text content
339
* @param flag - Patch flag for optimization
340
* @returns Text VNode
341
*/
342
function createTextVNode(text?: string, flag?: number): VNode;
343
344
/**
345
* Creates a comment VNode
346
* @param text - Comment text
347
* @param asBlock - Whether to create as block
348
* @returns Comment VNode
349
*/
350
function createCommentVNode(text?: string, asBlock?: boolean): VNode;
351
352
/**
353
* Creates a static VNode for hoisted content
354
* @param content - Static HTML content
355
* @param numberOfNodes - Number of nodes in content
356
* @returns Static VNode
357
*/
358
function createStaticVNode(content: string, numberOfNodes: number): VNode;
359
360
/**
361
* Creates an element VNode
362
* @param type - Element type
363
* @param props - Element properties
364
* @param children - Child nodes
365
* @param patchFlag - Optimization flag
366
* @param dynamicProps - Dynamic property names
367
* @returns Element VNode
368
*/
369
function createElementVNode(
370
type: string | typeof Fragment,
371
props?: VNodeProps | null,
372
children?: VNodeArrayChildren,
373
patchFlag?: number,
374
dynamicProps?: string[] | null
375
): VNode;
376
377
/**
378
* Creates an element block (tracked VNode)
379
* @param type - Element type
380
* @param props - Element properties
381
* @param children - Child nodes
382
* @param patchFlag - Optimization flag
383
* @param dynamicProps - Dynamic property names
384
* @returns Element block VNode
385
*/
386
function createElementBlock(
387
type: string,
388
props?: VNodeProps | null,
389
children?: VNodeArrayChildren,
390
patchFlag?: number,
391
dynamicProps?: string[] | null
392
): VNode;
393
```
394
395
## Types
396
397
```typescript { .api }
398
interface VNode<HostNode = RendererNode, HostElement = RendererElement> {
399
// Core properties
400
type: VNodeTypes;
401
props: VNodeProps | null;
402
key: string | number | symbol | null;
403
ref: VNodeRef | null;
404
children: VNodeNormalizedChildren;
405
406
// Internal properties
407
component: ComponentInternalInstance | null;
408
suspense: SuspenseBoundary | null;
409
ssrContext: Record<string, any> | null;
410
411
// Optimization
412
patchFlag: number;
413
dynamicProps: string[] | null;
414
dynamicChildren: VNode[] | null;
415
416
// Platform-specific
417
el: HostNode | null;
418
anchor: HostNode | null;
419
target: HostElement | null;
420
targetAnchor: HostNode | null;
421
}
422
423
type VNodeTypes = string | VNode | Component | typeof Text | typeof Static | typeof Comment | typeof Fragment;
424
425
interface VNodeProps {
426
key?: string | number | symbol;
427
ref?: VNodeRef;
428
ref_for?: boolean;
429
ref_key?: string;
430
431
// DOM properties
432
[key: string]: any;
433
}
434
435
type VNodeArrayChildren = Array<VNodeArrayChildren | VNodeChildAtom>;
436
437
type VNodeChildAtom = VNode | string | number | boolean | null | undefined | void;
438
439
type VNodeNormalizedChildren = string | VNodeArrayChildren | RawSlots | null;
440
441
interface VNodeRef {
442
(ref: Element | ComponentPublicInstance | null, refs: Record<string, any>): void;
443
}
444
445
type RendererNode = any;
446
type RendererElement = any;
447
448
interface Renderer<HostElement = RendererElement> {
449
render: RootRenderFunction<HostElement>;
450
createApp: CreateAppFunction<HostElement>;
451
}
452
453
interface HydrationRenderer extends Renderer<Element | ShadowRoot> {
454
hydrate: RootHydrateFunction;
455
}
456
457
type RootRenderFunction<HostElement = RendererElement> = (
458
vnode: VNode | null,
459
container: HostElement,
460
namespace?: ElementNamespace
461
) => void;
462
463
type ElementNamespace = 'svg' | 'mathml' | undefined;
464
```