Skip to content

Vue推荐在绝大多数情况下使用模版来创建你的HTML。然而在一些场景中,你真的需要JavaScript的完全编程的能力。这时可以用渲染函数render函数(字符串模版的代替方案,允许你发挥JavaScript最大的编程能力),它比模版更接近编译器。

js
<base-component :level="level">
	<p>
	This is {{ level }} 标题的内容
	</p>
</base-component>

export default {
  components: {
    BaseComponent
  },
  data () {
    return {
      level: 1
    }
  },
  methods: {
    changeLevel() {
      this.level ++;
    }
  }
}

当开始写一个只能通过level prop动态生成标题的组件时,可能很快想到这样实现

js
<template>
    <h1 v-if="level === 1">
        <slot></slot>
    </h1>
    <h2 v-else-if="level === 2">
        <slot></slot>
    </h2>
    <h3 v-else-if="level === 3">
        <slot></slot>
    </h3>
    <h4 v-else-if="level === 4">
        <slot></slot>
    </h4>
    <h5 v-else-if="level === 5">
        <slot></slot>
    </h5>
    <h6 v-else-if="level === 6">
        <slot></slot>
    </h6>
</template>

这里用模版并不是最好的选择:不但代码冗长,而且在每一个级别的标题中重复书写了, 在要插入元素时还要再次重复。虽然模版在大多数组中都非常好用,但是显然它在这里就不太合适了。那么我们用render函数重写上面的例子:

js
props: {
	level: {
			type: Number,
			default: 0,
			require: true
	}
}

<script>
	export default {
		render(h) {
			return h(
				'h' + this.level,
				null,
				this.$slot.default
			)
		}
	}
</script>

节点、树以及虚拟DOM

html
<div>
    <h1>My title</h1>
    some text content
    <!-- TODO: Add tagline -->
</div>

当浏览器读到这些代码时,它会建立一个“DOM节点”树来保持追踪所有内容,如同你会画一张家谱树来追踪家庭成员的发展一样。上述HTMl对应的DOM节点树入下图所示:

每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点(也就是说每个部分都可以包含其它的一些部分)。高效的更新这些节点会是比较困难的,不过不必动手完成这个工作。只需要告诉Vue你希望页面上的HTML是什么,这可以是是在一个模版里

js
<h1> {{ blogTitle }} </h1>

render: function(h) {
	return h('h1', null, this.blogTitle);
}

虚拟DOM

Vue通过建立一个虚拟DOM来追逐自己要如何改变真实DOM

js
return h('h1', null, this.blogTitle)

h函数其实返回的不是一个实际的DOM元素。它更准确的名字可能是createNodeDescription,因为它所包含的信息会告诉Vue页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点virtual node,”也常简写它为VNode。“虚拟DOM”是我们对由Vue组件树建立起来的整个VNode树的称呼。

h函数的参数

js
// @returns {VNode}
h(
    // {String | Object | Function}
    // 一个 HTML 标签名、组件选项对象,或者
    // resolve 了上述任何一种的一个 async 函数。必填项。
    'div',

    // {Object}
    // 一个与模板中 attribute 对应的数据对象。可选。
    {},

    // {String | Array}
    // 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
    // 也可以使用字符串来生成“文本虚拟节点”。可选。
    [
        '先写一些文字',
        createElement('h1', '一则头条'),
        createElement(MyComponent, {
            props: {
                someProp: 'foobar'
            }
        })
    ]
)