在 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>