@@ -19,8 +19,11 @@ Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在
1919```
2020
2121当开始写一个只能通过 ` level ` prop 动态生成标题 (heading) 的组件时,我们很快就可以得出这样的结论:
22+
2223``` js
23- const app = Vue .createApp ({})
24+ const { createApp } = Vue
25+
26+ const app = createApp ({})
2427
2528app .component (' anchored-heading' , {
2629 template: `
@@ -51,17 +54,18 @@ app.component('anchored-heading', {
5154 }
5255})
5356```
57+
5458这个模板感觉不太好。它不仅冗长,而且我们为每个级别标题重复书写了 ` <slot></slot> ` 。当我们添加锚元素时,我们必须在每个 ` v-if/v-else-if ` 分支中再次重复它。
5559
5660虽然模板在大多数组件中都非常好用,但是显然在这里它就不合适了。那么,我们来尝试使用 ` render ` 函数重写上面的例子:
5761
5862``` js
59- const app = Vue .createApp ({})
63+ const { createApp , h } = Vue
64+
65+ const app = createApp ({})
6066
6167app .component (' anchored-heading' , {
6268 render () {
63- const { h } = Vue
64-
6569 return h (
6670 ' h' + this .level , // tag name
6771 {}, // props/attributes
@@ -109,7 +113,7 @@ app.component('anchored-heading', {
109113
110114``` js
111115render () {
112- return Vue . h (' h1' , {}, this .blogTitle )
116+ return h (' h1' , {}, this .blogTitle )
113117}
114118```
115119
@@ -120,7 +124,7 @@ render() {
120124Vue 通过建立一个** 虚拟 DOM** 来追踪自己要如何改变真实 DOM。请仔细看这行代码:
121125
122126``` js
123- return Vue . h (' h1' , {}, this .blogTitle )
127+ return h (' h1' , {}, this .blogTitle )
124128```
125129
126130` h() ` 到底会返回什么呢?其实不是一个* 实际* 的 DOM 元素。它更准确的名字可能是 createNodeDescription,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为 ** VNode** 。“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。
167171有了这些知识,我们现在可以完成我们最开始想实现的组件:
168172
169173``` js
170- const app = Vue .createApp ({})
174+ const { createApp , h } = Vue
175+
176+ const app = createApp ({})
171177
172178/** Recursively get text from children nodes */
173179function getChildrenTextContent (children ) {
@@ -190,8 +196,8 @@ app.component('anchored-heading', {
190196 .replace (/ \W + / g , ' -' ) // replace non-word characters with dash
191197 .replace (/ (^ -| -$ )/ g , ' ' ) // remove leading and trailing dashes
192198
193- return Vue . h (' h' + this .level , [
194- Vue . h (
199+ return h (' h' + this .level , [
200+ h (
195201 ' a' ,
196202 {
197203 name: headingId,
@@ -218,8 +224,8 @@ app.component('anchored-heading', {
218224
219225``` js
220226render () {
221- const myParagraphVNode = Vue . h (' p' , ' hi' )
222- return Vue . h (' div' , [
227+ const myParagraphVNode = h (' p' , ' hi' )
228+ return h (' div' , [
223229 // 错误 - 重复的Vnode!
224230 myParagraphVNode, myParagraphVNode
225231 ])
@@ -230,9 +236,9 @@ render() {
230236
231237``` js
232238render () {
233- return Vue . h (' div' ,
239+ return h (' div' ,
234240 Array .from ({ length: 20 }).map (() => {
235- return Vue . h (' p' , ' hi' )
241+ return h (' p' , ' hi' )
236242 })
237243 )
238244}
@@ -257,24 +263,24 @@ render() {
257263props: [' items' ],
258264render () {
259265 if (this .items .length ) {
260- return Vue . h (' ul' , this .items .map ((item ) => {
261- return Vue . h (' li' , item .name )
266+ return h (' ul' , this .items .map ((item ) => {
267+ return h (' li' , item .name )
262268 }))
263269 } else {
264- return Vue . h (' p' , ' No items found.' )
270+ return h (' p' , ' No items found.' )
265271 }
266272}
267273```
268274
269275### ` v-model `
270276
271- ` v-model ` 指令扩展为 ` modelValue ` 和 ` onUpdate:modelValue ` 在模板编译过程中,我们必须自己提供这些prop :
277+ ` v-model ` 指令扩展为 ` modelValue ` 和 ` onUpdate:modelValue ` 在模板编译过程中,我们必须自己提供这些 prop :
272278
273279``` js
274280props: [' modelValue' ],
275281emits: [' update:modelValue' ],
276282render () {
277- return Vue . h (SomeComponent, {
283+ return h (SomeComponent, {
278284 modelValue: this .modelValue ,
279285 ' onUpdate:modelValue ' : value => this .$emit (' update:modelValue' , value)
280286 })
@@ -283,25 +289,25 @@ render() {
283289
284290### ` v-on `
285291
286- 我们必须为事件处理程序提供一个正确的prop名称 ,例如,要处理 ` click ` 事件,prop名称应该是 ` onClick ` 。
292+ 我们必须为事件处理程序提供一个正确的 prop 名称 ,例如,要处理 ` click ` 事件,prop 名称应该是 ` onClick ` 。
287293
288294``` js
289295render () {
290- return Vue . h (' div' , {
296+ return h (' div' , {
291297 onClick : $event => console .log (' clicked' , $event .target )
292298 })
293299}
294300```
295301
296302#### 事件修饰符
297303
298- 对于 ` .passive ` 、 ` .capture ` 和 ` .once ` 事件修饰符,Vue提供了处理程序的对象语法 :
304+ 对于 ` .passive ` 、 ` .capture ` 和 ` .once ` 事件修饰符,Vue 提供了处理程序的对象语法 :
299305
300306实例:
301307
302308``` javascript
303309render () {
304- return Vue . h (' input' , {
310+ return h (' input' , {
305311 onClick: {
306312 handler: this .doThisInCapturingMode ,
307313 capture: true
@@ -321,19 +327,19 @@ render() {
321327
322328对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:
323329
324- | 修饰符 | 处理函数中的等价操作 |
325- | ----------------------------------------------------- | -------- ------------------------------------------------------------------------------------------------------------ |
326- | ` .stop ` | ` event.stopPropagation() ` |
327- | ` .prevent ` | ` event.preventDefault() ` |
328- | ` .self ` | ` if (event.target !== event.currentTarget) return ` |
329- | 按键:<br >` .enter ` , ` .13 ` | ` if (event.keyCode !== 13) return ` (对于别的按键修饰符来说,可将 13 改为[ 另一个按键码] ( http://keycode.info/ ) |
330- | 修饰键:<br >` .ctrl ` , ` .alt ` , ` .shift ` , ` .meta ` | ` if (!event.ctrlKey) return ` (将 ` ctrlKey ` 分别修改为 ` altKey ` , ` shiftKey ` , 或 ` metaKey ` ) |
330+ | 修饰符 | 处理函数中的等价操作 |
331+ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
332+ | ` .stop ` | ` event.stopPropagation() ` |
333+ | ` .prevent ` | ` event.preventDefault() ` |
334+ | ` .self ` | ` if (event.target !== event.currentTarget) return ` |
335+ | 按键:<br >` .enter ` , ` .13 ` | ` if (event.keyCode !== 13) return ` (对于别的按键修饰符来说,可将 13 改为[ 另一个按键码] ( http://keycode.info/ ) |
336+ | 修饰键:<br >` .ctrl ` , ` .alt ` , ` .shift ` , ` .meta ` | ` if (!event.ctrlKey) return ` (将 ` ctrlKey ` 分别修改为 ` altKey ` , ` shiftKey ` , 或 ` metaKey ` ) |
331337
332338这里是一个使用所有修饰符的例子:
333339
334340``` js
335341render () {
336- return Vue . h (' input' , {
342+ return h (' input' , {
337343 onKeyUp : event => {
338344 // 如果触发事件的元素不是事件绑定的元素
339345 // 则返回
@@ -358,15 +364,15 @@ render() {
358364``` js
359365render () {
360366 // `<div><slot></slot></div>`
361- return Vue . h (' div' , {}, this .$slots .default ())
367+ return h (' div' , {}, this .$slots .default ())
362368}
363369```
364370
365371``` js
366372props: [' message' ],
367373render () {
368374 // `<div><slot :text="message"></slot></div>`
369- return Vue . h (' div' , {}, this .$slots .default ({
375+ return h (' div' , {}, this .$slots .default ({
370376 text: this .message
371377 }))
372378}
@@ -377,11 +383,13 @@ render() {
377383<!-- TODO: translation -->
378384
379385``` js
386+ const { h , resolveComponent } = Vue
387+
380388render () {
381389 // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
382- return Vue . h (' div' , [
383- Vue . h (
384- Vue . resolveComponent (' child' ),
390+ return h (' div' , [
391+ h (
392+ resolveComponent (' child' ),
385393 {},
386394 // pass `slots` as the children object
387395 // in the form of { name: props => VNode | Array<VNode> }
@@ -398,13 +406,13 @@ render() {
398406如果你写了很多渲染函数,可能会觉得下面这样的代码写起来很痛苦:
399407
400408``` js
401- Vue . h (
409+ h (
402410 ' anchored-heading' ,
403411 {
404412 level: 1
405413 },
406414 {
407- default : () => [Vue . h (' span' , ' Hello' ), ' world!' ]
415+ default : () => [h (' span' , ' Hello' ), ' world!' ]
408416 }
409417)
410418```
0 commit comments