Skip to content

Commit eaf6f96

Browse files
committed
api: render function
1 parent 07cb4ed commit eaf6f96

File tree

3 files changed

+279
-24
lines changed

3 files changed

+279
-24
lines changed

.prettierrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"semi": false,
33
"singleQuote": true,
4-
"trailingComma": "none"
4+
"trailingComma": "none",
5+
"printWidth": 75
56
}

src/api/render-function.md

+268-22
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,294 @@
22

33
## h()
44

5+
Creates virtual DOM nodes (vnodes).
6+
7+
- **Type**
8+
9+
```ts
10+
// full signature
11+
function h(
12+
type: string | Component,
13+
props?: object | null,
14+
children?: Children | Slot | Slots
15+
): VNode
16+
17+
// omitting props
18+
function h(type: string | Component, children?: Children | Slot): VNode
19+
20+
type Children = string | number | boolean | VNode | null | Children[]
21+
22+
type Slot = () => Children
23+
24+
type Slots = { [name: string]: Slot }
25+
```
26+
27+
> Types are simplified for readability.
28+
29+
- **Details**
30+
31+
The first argument can either be a string (for native elements) or a Vue component definition. The second argument is the props to be passed, and the third argument is the children.
32+
33+
When creating a component vnode, the children must be passed as slot functions. A single slot function can be passed if the component expects only the default slot. Otherwise, the slots must be passed as an object of slot functions.
34+
35+
For convenience, the props argument can be omitted when the children is not a slots object.
36+
37+
- **Example**
38+
39+
Creating native elements:
40+
41+
```js
42+
import { h } from 'vue'
43+
44+
// all arguments except the type are optional
45+
h('div')
46+
h('div', { id: 'foo' })
47+
48+
// both attributes and properties can be used in props
49+
// Vue automatically picks the right way to assign it
50+
h('div', { class: 'bar', innerHTML: 'hello' })
51+
52+
// class and style have the same object / array
53+
// value support like in templates
54+
h('div', { class: [foo, { bar }], style: { color: 'red' } })
55+
56+
// event listeners should be passed as onXxx
57+
h('div', { onClick: () => {} })
58+
59+
// children can be a string
60+
h('div', { id: 'foo' }, 'hello')
61+
62+
// props can be omitted when there are no props
63+
h('div', 'hello')
64+
h('div', [h('span', 'hello')])
65+
66+
// children array can contain mixed vnodes and strings
67+
h('div', ['hello', h('span', 'hello')])
68+
```
69+
70+
Creating components:
71+
72+
```js
73+
import Foo from './Foo.vue'
74+
75+
// passing props
76+
h(Foo, {
77+
// equivalent of some-prop="hello"
78+
someProp: 'hello',
79+
// equivalent of @update="() => {}"
80+
onUpdate: () => {}
81+
})
82+
83+
// passing single default slot
84+
h(Foo, () => 'default slot')
85+
86+
// passing named slots
87+
// notice the `null` is required to avoid
88+
// slots object being treated as props
89+
h(MyComponent, null, {
90+
default: () => 'default slot',
91+
foo: () => h('div', 'foo'),
92+
bar: () => [h('span', 'one'), h('span', 'two')]
93+
})
94+
```
95+
96+
- See also: [Guide - Creating VNodes](/guide/extras/render-function.html#creating-vnodes)
97+
598
## mergeProps()
699

100+
Merge multiple props objects with special handling for certain props.
101+
102+
- **Type**
103+
104+
```ts
105+
function mergeProps(...args: object[]): object
106+
```
107+
108+
- **Details**
109+
110+
`mergeProps()` supports merging multiple props objects with special handling for the following props:
111+
112+
- `class`
113+
- `style`
114+
- `onXxx` event listeners - multiple listeners with the same name will be merged into an array.
115+
116+
If you do not need the merge behavior and want simple overwrites, native object spread can be used instead.
117+
118+
- **Example**
119+
120+
```js
121+
import { mergeProps } from 'vue'
122+
123+
const one = {
124+
class: 'foo',
125+
onClick: handlerA
126+
}
127+
128+
const two = {
129+
class: { bar: true },
130+
onClick: handlerB
131+
}
132+
133+
const merged = mergeProps(one, two)
134+
/**
135+
{
136+
class: 'foo bar',
137+
onClick: [handlerA, handlerB]
138+
}
139+
*/
140+
```
141+
7142
## cloneVNode()
8143

144+
Clones a vnode.
145+
146+
- **Type**
147+
148+
```ts
149+
function cloneVNode(vnode: VNode, extraProps?: object): VNode
150+
```
151+
152+
- **Details**
153+
154+
Returns a cloned vnode, optionally with extra props to merge with the original.
155+
156+
Vnodes should be considered immutable once created, and you should not mutate the props of an existing vnode. Instead, clone it with different / extra props.
157+
158+
Vnodes have special internal properties, so cloning them is not as simple as an object spread. `cloneVNode()` handles most of the internal logic.
159+
160+
- **Example**
161+
162+
```js
163+
import { h, cloneVNode } from 'vue'
164+
165+
const original = h('div')
166+
const cloned = cloneVNode(original, { id: 'foo' })
167+
```
168+
9169
## isVNode()
10170

171+
Checks if a value is a vnode.
172+
173+
- **Type**
174+
175+
```ts
176+
function isVNode(value: unknown): boolean
177+
```
178+
11179
## resolveComponent()
12180

13-
<div class="composition-api">
181+
For manually resolving a registered component by name.
14182

15-
```js
16-
const { h, resolveComponent } = Vue
183+
- **Type**
17184

18-
export default {
19-
setup() {
20-
const ButtonCounter = resolveComponent('ButtonCounter')
185+
```ts
186+
function resolveComponent(name: string): Component | string
187+
```
21188

22-
return () => {
23-
return h(ButtonCounter)
189+
- **Details**
190+
191+
**Note: you do not need this if you can import the component directly.**
192+
193+
`resolveComponent()` must be called inside<span class="composition-api"> either `setup()` or</span> the render function in order to resolve from the correct component context.
194+
195+
If the component is not found, a runtime warning will be emitted, and the name string is returned.
196+
197+
- **Example**
198+
199+
<div class="composition-api">
200+
201+
```js
202+
const { h, resolveComponent } = Vue
203+
204+
export default {
205+
setup() {
206+
const ButtonCounter = resolveComponent('ButtonCounter')
207+
208+
return () => {
209+
return h(ButtonCounter)
210+
}
24211
}
25212
}
26-
}
27-
```
213+
```
28214

29-
</div>
30-
<div class="options-api">
215+
</div>
216+
<div class="options-api">
31217

32-
```js
33-
const { h, resolveComponent } = Vue
218+
```js
219+
const { h, resolveComponent } = Vue
34220
35-
export default {
36-
render() {
37-
const ButtonCounter = resolveComponent('ButtonCounter')
38-
return h(ButtonCounter)
221+
export default {
222+
render() {
223+
const ButtonCounter = resolveComponent('ButtonCounter')
224+
return h(ButtonCounter)
225+
}
39226
}
40-
}
41-
```
227+
```
42228

43-
</div>
229+
</div>
44230

45-
Note that `resolveComponent()` must be called inside<span class="composition-api">either `setup()` or</span> the render function in order to resolve from the correct component context.
231+
- **See also:** [Guide - Render Functions - Components](/guide/extras/render-function.html#components)
46232

47233
## resolveDirective()
48234

235+
For manually resolving a registered directive by name.
236+
237+
- **Type**
238+
239+
```ts
240+
function resolveDirective(name: string): Directive | undefined
241+
```
242+
243+
- **Details**
244+
245+
**Note: you do not need this if you can import the component directly.**
246+
247+
`resolveDirective()` must be called inside<span class="composition-api"> either `setup()` or</span> the render function in order to resolve from the correct component context.
248+
249+
If the directive is not found, a runtime warning will be emitted, and the function returns `undefined`.
250+
251+
- **See also:** [Guide - Render Functions - Custom Directives](guide/extras/render-function.html#custom-directives)
252+
49253
## withDirectives()
254+
255+
For adding custom directives to vnodes.
256+
257+
- **Type**
258+
259+
```ts
260+
function withDirectives(
261+
vnode: VNode,
262+
directives: DirectiveArguments
263+
): VNode
264+
265+
// [Directive, value, argument, modifiers]
266+
type DirectiveArguments = Array<
267+
| [Directive]
268+
| [Directive, any]
269+
| [Directive, any, string]
270+
| [Directive, any, string, DirectiveModifiers]
271+
>
272+
```
273+
274+
- **Details**
275+
276+
Wraps an existing vnode with custom directives. The second argument is an array of custom directives. Each custom directive is also represented as an array in the form of `[Directive, value, argument, modifiers]`. Tailing elements of the array can be omitted if not needed.
277+
278+
- **Example**
279+
280+
```js
281+
import { h, withDirectives } from Vue
282+
283+
// a custom directive
284+
const pin = {
285+
mounted() { /* ... */ },
286+
updated() { /* ... */ }
287+
}
288+
289+
// <div v-pin:top.animate="200"></div>
290+
const vnode = withDirectives(h('div'), [
291+
[pin, 200, 'top', { animate: true }]
292+
])
293+
```
294+
295+
- **See also:** [Guide - Render Functions - Custom Directives](guide/extras/render-function.html#custom-directives)

src/guide/extras/render-function.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ h('div', { id: 'foo' })
3939
// Vue automatically picks the right way to assign it
4040
h('div', { class: 'bar', innerHTML: 'hello' })
4141

42+
// class and style have the same object / array
43+
// value support like in templates
44+
h('div', { class: [foo, { bar }], style: { color: 'red' } })
45+
46+
// event listeners should be passed as onXxx
47+
h('div', { onClick: () => {} })
48+
4249
// children can be a string
4350
h('div', { id: 'foo' }, 'hello')
4451

@@ -196,7 +203,8 @@ If you really want to duplicate the same element/component many times, you can d
196203

197204
```js
198205
function render() {
199-
return h('div',
206+
return h(
207+
'div',
200208
Array.from({ length: 20 }).map(() => {
201209
return h('p', 'hi')
202210
})

0 commit comments

Comments
 (0)