Vue.js 模板非常强大,几乎可以完成您在应用程序中需要的所有内容。 但是,有一些用例,通常涉及基于输入或槽值的动态组件创建,渲染函数更好地服务。
那些来自 React 世界的人可能对渲染函数非常熟悉。 React 组件是用它们构建的,通常通过 JSX。 虽然 Vue 渲染函数也可以使用 JSX 编写,但我们将坚持使用原始 JS,以便您可以更轻松地了解 Vue 组件系统的基础。
值得注意的是,Vue.js 的模板实际上会在构建时编译为渲染函数。 模板只是在渲染函数之上提供了一种方便且熟悉的语法糖。 尽管渲染功能更强大,但在可读性方面经常受到影响。
创建组件
具有 渲染功能 的组件没有模板标记或属性。 相反,他们定义了一个名为 render 的函数,该函数接收 createElement(renderElement: String | Component, definition: Object, children: String | Array) 参数(通常别名为 h[ X209X],出于某种原因,归咎于 JSX)并返回使用该函数创建的元素。 其他一切都保持不变。
ExampleComponent.vue
export default { data() { return { isRed: true } }, /* * Same as * <template> * <div :class="{'is-red': isRed}"> * <p>Example Text</p> * </div> * </template> */ render(h) { return h('div', { 'class': { 'is-red': this.isRed } }, [ h('p', 'Example Text') ]) } }
替换速记指令
Vue 模板带有各种方便的功能,以便为模板添加基本逻辑和绑定功能。 渲染函数无权访问这些。 相反,它们必须用纯 Javascript 实现,对于大多数指令来说,这相当简单。
v-如果
这很容易。 不要使用 v-if,只需在 createElement 调用周围使用普通的 Javascript if (expr) 语句即可。
v-for
v-for 可以使用许多 Javascript 迭代方法中的任何一种来实现,for、for-of、Array.map、Array.filter 等 。 您可以以非常有趣的方式将这些组合起来以实现过滤或状态切片,而无需计算属性。
例如,您可以替换
<template> <ul> <li v-for="pea of pod"> {{pea.name}} </li> </ul> </template>
和
render(h) { return h('ul', this.pod.map(pea => h('li', pea.name))); }
v型
要记住的一件好事是,v-model 只是将属性绑定到 value 并在触发 input 事件时设置数据属性的简写. 不幸的是,渲染函数没有这样的简写。 您必须自己实现它,如下所示。
render(h) { return h('input', { domProps: { value: this.myBoundProperty }, on: { input: e => { this.myBoundProperty = e.target.value } } }) }
这相当于:
<template> <input :value="myBoundProperty" @input="myBoundProperty = $event.target.value"/> </template>
或者
<template> <input v-model="myBoundProperty"/> </template>
v-绑定
属性和属性绑定放在元素定义中,如 arttrs、props 和 domProps(类似 value 和 内部HTML )。
render(h) { return h('div', { attrs: { // <div :id="myCustomId"> id: this.myCustomId }, props: { // <div :someProp="someonePutSomethingHere"> someProp: this.someonePutSomethingHere }, domProps: { // <div :value="somethingElse"> value: this.somethingElse } }); }
附带说明一下,类和样式绑定直接在定义的根处处理,而不是作为 attrs、props 或 domProps。
render(h) { return h('div', { // "class" is a reserved keyword in JS, so you have to quote it. 'class': { myClass: true, theirClass: false }, style: { backgroundColor: 'green' } }); }
开启
事件处理程序也直接添加到元素定义中,在 on (或 nativeOn 中,与组件的 v-on.native 具有相同的效果)。 )
render(h) { return h('div', { on: { click(e) { console.log('I got clickeded!') } } }); }
修饰符可以在处理程序内部实现:
- .stop -> e.stopPropagation()
- .prevent -> e.preventDefault()
- .self -> if (e.target !== e.currentTarget) 返回
键盘修饰符
- .[TARGET_KEY_CODE] -> if (event.keyCode !== TARGET_KEY_CODE) 返回
- .[MODIFIER] -> if (!event.MODIFIERKey) 返回
特殊属性
Slots 可以通过 this.$slots 作为 createElement() 节点的数组来访问。
作用域插槽存储在 this.$scopedSlots[scope](props: object) 作为返回 createElement() 节点数组的函数。
享受渲染功能赋予您的新的、无限的力量! 请小心谨慎使用。