在 Vue 中除了使用 template 模板外,还可以使用 render 函数(优先级高于 template)。
render 函数接收一个 createElement 函数作为参数,返回 VNode(虚拟节点)。
10-1.createElement
createElement 函数是 Vue 提供的,用于创建 VNode。也可以使用别名 h。
基本格式如下:
js
// https://v2.cn.vuejs.org/v2/guide/render-function.html
const render = function (createElement) {
// @returns {VNode}
return createElement(
// {String | Object | Function}
// 一个 HTML 标签名、组件选项对象,或者
// resolve 了上述任何一种的一个 async 函数。必填项。
'div',
// {Object} vue2-render-attrs
// 一个与模板中 attribute 对应的数据对象。可选。
{
},
// {String | Array}
// 子级虚拟节点 (VNodes),由 `createElement()` 构建而成,
// 也可以使用字符串来生成“文本虚拟节点”。可选。
[
'Hello World',
createElement('h1', '你好'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
)
}vue2-render-attrs 详细补充如下:
js
render (h) {
return h('div', {
// Component props
props: {
msg: 'hi',
onCustomEvent: this.customEventHandler
},
// normal HTML attributes
attrs: {
id: 'foo'
},
// DOM props
domProps: {
innerHTML: 'bar'
},
// Event handlers are nested under "on", though
// modifiers such as in v-on:keyup.enter are not
// supported. You'll have to manually check the
// keyCode in the handler instead.
on: {
click: this.clickHandler
},
// For components only. Allows you to listen to
// native events, rather than events emitted from
// the component using vm.$emit.
nativeOn: {
click: this.nativeClickHandler
},
// class is a special module, same API as `v-bind:class`
class: {
foo: true,
bar: false
},
// style is also same as `v-bind:style`
style: {
color: 'red',
fontSize: '14px'
},
// other special top-level properties
key: 'key',
ref: 'ref',
// assign the `ref` is used on elements/components with v-for
refInFor: true,
slot: 'slot'
}, [
'Hello World',
h('h1', '你好'),
h(MyComponent, {
props: {
someProp: 'foobar'
}
})
])
}10-2.jsx
在业务中直接使用 createElement 函数,比较繁琐,因此 Vue 提供了 jsx 语法简化操作。
js
const render = function (h) {
return (
<div
// normal attributes or prefix with on props.
id="foo"
propsOnCustomEvent={this.customEventHandler}
// DOM properties are prefixed with `domProps`
domPropsInnerHTML="bar"
// event listeners are prefixed with `on` or `nativeOn`
onClick={this.clickHandler}
nativeOnClick={this.nativeClickHandler}
// other special top-level properties
class={{ foo: true, bar: false }}
style={{ color: 'red', fontSize: '14px' }}
key="key"
ref="ref"
// assign the `ref` is used on elements/components with v-for
refInFor
slot="slot">
Hello World
<h1>你好</h1>
<MyComponent someProp="foobar" />
</div>
)
}如果要在 Vue 项目中使用 jsx,则需要安装 babel 插件。
- 如果是
babel@7,那么:
bash
pnpm add @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props -D在 babel.config.js 中配置:
js
module.exports = {
presets: ['@vue/babel-preset-jsx']
}- 如果是
babel@6,那么:
bash
pnpm add babel-plugin-transform-vue-jsx -D在 babel.config.js 中配置:
js
module.exports = {
plugins: ['transform-vue-jsx']
}额外链接补充:
babel插件:babel-plugin-transform-vue-jsx- 核心库:jsx-vue2
10-3.functional
假设一个组件没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法。而只是一个接受一些 prop。
那么这个组件,我们可以改造成函数式组件。
事实上,这个函数式组件就是一个接受 props 并返回 VNode 的函数。因此函数式组件的特性有:
- 没有响应式数据
- 没有
this上下文,全局状态通过context获取 - 没有生命周期方法
10-3-1.context
函数式组件没有 this 上下文,但是需要访问组件 props、slots 、scopedSlots 等属性,因此 Vue 提供了 context 上下文。
context 对象包含以下属性:
props:提供所有prop的对象;children:VNode子节点的数组;slots:一个函数,返回了包含所有插槽的对象;scopedSlots:(2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽;data:传递给组件的整个数据对象,作为createElement的第二个参数传入组件;parent:对父组件的引用;listeners:(2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是data.on的一个别名;injections:(2.3.0+) 如果使用了inject选项,则该对象包含了应当被注入的property。
10-3-2.JS语法
我们可以使用 template 或者 render 函数来声明函数式组件。
以 render 函数为例:
js
const MyComponent = {
functional: true,
props: {
msg: {
type: String,
default: 'Hello World'
}
},
render (h, context) {
return (
<div>{context.props.msg}</div>
)
}
}10-3-3.vue单文件语法
在 vue 单文件组件中,使用 functional 属性在 <template> 标签上声明,这样 vue 会自动将 context 作为上下文传入。
这样我们就可以在模板中直接使用 props 访问 prop 数据。
vue
<template functional>
<div>{{ props.msg }}</div>
</template>