Skip to content

Commit 2d24890

Browse files
committed
完善render函数文档
1 parent a645621 commit 2d24890

File tree

2 files changed

+137
-1
lines changed

2 files changed

+137
-1
lines changed
29.9 KB
Loading

docs/posts/tutorial/6.md

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
# render 函数组件
22

3+
```html
4+
<!-- HTML -->
5+
<script type="text/x-template" id="anchored-heading-template">
6+
<h1 v-if="level === 1"> <slot></slot> </h1>
7+
<h2 v-else-if="level === 2"> <slot></slot> </h2>
8+
<h3 v-else-if="level === 3"> <slot></slot> </h3>
9+
<h4 v-else-if="level === 4"> <slot></slot> </h4>
10+
<h5 v-else-if="level === 5"> <slot></slot> </h5>
11+
<h6 v-else-if="level === 6"> <slot></slot> </h6>
12+
</script>
13+
<!-- Javascript -->
14+
<script>
15+
Vue.component('anchored-heading', { template: '#anchored-heading-template', props: { level: { type: Number,required: true } } })
16+
</script>
17+
```
18+
19+
这是我从网上找的一个非常常见的案例,大部分关于渲染函数的文章可能都会使用这个案例来说明在这种场景下使用template并不是最好的选择,首先是代码冗长,其次重复使用了slot,虽然一眼看上去简单明了,但这是不是最简单的写法,下面是更加简洁的render函数的写法:
20+
21+
```html
22+
<script>
23+
Vue.components('anchored-heading', {
24+
render: function (h) => {
25+
return h(`h${this.level}`, this.slot.default)
26+
},
27+
props: { level: { type: Number,required: true } }
28+
})
29+
</script>
30+
```
31+
332
## vue组件的渲染过程
433
![](/img/vue-render-1.jpg)
534
![](/lai-ui/img/vue-render-1.jpg)
@@ -37,7 +66,6 @@ module.exports = {
3766

3867
vue实例中有个$mount函数,通常我们在手动挂载组件的时候会用到这个方法,$mount是整个渲染过程的起始点。所谓手动挂载就是去手动让组件渲染,关于$mount的实践我在全局组件章节有提到,之后我们在vue的测试章节也会使用到。
3968

40-
4169
![](/img/vue-render-5.png)
4270
![](/lai-ui/img/vue-render-5.png)
4371

@@ -129,6 +157,11 @@ new Vue({
129157

130158
render函数默认接受一个h的参数,有的时候别人也会将h换成`createElement`,这样的话函数更加明显。
131159

160+
我们接下来从上边这段代码出发结合部分[源代码](https://github.com/vuejs/vue/blob/2.6/dist/vue.common.dev.js)大概了解一下一个vue的实例化过程:
161+
162+
![](/img/new-vue.png)
163+
![](/lai-ui/img/new-vue.png)
164+
132165
我们回到上边的`$mount`源码的部分,在编译成render函数之后,之后调用了运行时版本的`$mount`这个函数,我们把这个代码截取出来:
133166

134167
```js
@@ -284,10 +317,113 @@ Vue.prototype._render = function () {
284317

285318
`第一个参数:String | Object | function `
286319

320+
```js
321+
Vue.component('custom-element', {
322+
render: function (createElement) {
323+
return createElement('div')
324+
}
325+
})
326+
327+
Vue.component('custom-element', {
328+
render: function (createElement) {
329+
return createElement({ template: `<div>Hello Vue!</div>` })
330+
}
331+
})
332+
333+
Vue.component('custom-element', {
334+
render: function (createElement) {
335+
var eleFun = function () {
336+
return { template: `<div>Hello Vue!</div>` }
337+
}
338+
return createElement(eleFun())
339+
}
340+
})
341+
```
287342
`第二个参数是一个可选的数据对象`,这个说明还是看文档吧。
288343

344+
```js
345+
{
346+
// 与 `v-bind:class` 的 API 相同,
347+
// 接受一个字符串、对象或字符串和对象组成的数组
348+
'class': {
349+
foo: true,
350+
bar: false
351+
},
352+
// 与 `v-bind:style` 的 API 相同,
353+
// 接受一个字符串、对象,或对象组成的数组
354+
style: {
355+
color: 'red',
356+
fontSize: '14px'
357+
},
358+
// 普通的 HTML 特性
359+
attrs: {
360+
id: 'foo'
361+
},
362+
// 组件 prop
363+
props: {
364+
myProp: 'bar'
365+
},
366+
// DOM 属性
367+
domProps: {
368+
innerHTML: 'baz'
369+
},
370+
// 事件监听器在 `on` 属性内,
371+
// 但不再支持如 `v-on:keyup.enter` 这样的修饰器。
372+
// 需要在处理函数中手动检查 keyCode。
373+
on: {
374+
click: this.clickHandler
375+
},
376+
// 仅用于组件,用于监听原生事件,而不是组件内部使用
377+
// `vm.$emit` 触发的事件。
378+
nativeOn: {
379+
click: this.nativeClickHandler
380+
},
381+
// 自定义指令。注意,你无法对 `binding` 中的 `oldValue`
382+
// 赋值,因为 Vue 已经自动为你进行了同步。
383+
directives: [
384+
{
385+
name: 'my-custom-directive',
386+
value: '2',
387+
expression: '1 + 1',
388+
arg: 'foo',
389+
modifiers: {
390+
bar: true
391+
}
392+
}
393+
],
394+
// 作用域插槽的格式为
395+
// { name: props => VNode | Array<VNode> }
396+
scopedSlots: {
397+
default: props => createElement('span', props.text)
398+
},
399+
// 如果组件是其它组件的子组件,需为插槽指定名称
400+
slot: 'name-of-slot',
401+
// 其它特殊顶层属性
402+
key: 'myKey',
403+
ref: 'myRef',
404+
// 如果你在渲染函数中给多个元素都应用了相同的 ref 名,
405+
// 那么 `$refs.myRef` 会变成一个数组。
406+
refInFor: true
407+
}
408+
```
409+
289410
`第三个参数是children: String | Array`
290411

412+
```js
413+
Vue.component('custom-element', {
414+
render: function (createElement) {
415+
var self = this return createElement(
416+
// 第一个参数是一个简单的HTML标签字符 “必选”
417+
'div',
418+
// 第二个参数是一个包含模板相关属性的数据对象 “可选”
419+
{ class: { title: true }, style: { border: '1px solid', padding: '10px' } },
420+
// 第三个参数是传了多个子元素的一个数组 “可选”
421+
[ createElement('h1', 'Hello Vue!'), createElement('p', '开始学习Vue!') ]
422+
)
423+
}
424+
})
425+
```
426+
291427
关于createElement这个函数是如何解析我们传入的内容,这部分可以在Vue源代码中搜索`createElement`这个函数自行了解,也可以去网上查阅类似专门分析的文章,我之前没有关心这部分内容,所以这里不做讲解。
292428

293429

0 commit comments

Comments
 (0)