1. 函数式组件
我们可以把函数式组件想像成组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的HTML
函数式组件拥有两个特性:
- Stateless(无状态):组件自身是没有状态的
- Instanceless(无实例):组件自身没有实例,也就是没有this
Vue.component('my-component', {
functional: true,
// Props 是可选的
props: {
// ...
},
// 为了弥补缺少的实例
// 提供第二个参数作为上下文
render: function (createElement, context) {
// ...
}
})
<template functional>
<button
class="btn btn-primary"
v-bind="data.attrs"
v-on="listeners"
>
<slot/>
</button>
</template>
在一个 *.vue 文件中以单文件形式定义的函数式组件,现在对于模板编译、scoped CSS 和热重载也有了良好的支持。
要声明一个应该编译为函数式组件的模板,请将 functional 特性添加到模板块中。这样做以后就可以省略 <script> 块中的 functional 选项。
模板中的表达式会在函数式渲染上下文中求值。这意味着在模板中,prop 需要以 props.xxx 的形式访问:
<template functional>
<div>{{ props.foo }}</div>
</template>
你可以在 parent 上访问 Vue.prototype 全局定义的属性:
<template functional>
<div>{{ parent.$someProperty }}</div>
</template>
2. 自定义块——.vue文件
在 .vue 文件中,可以自定义语言块。应用于一个自定义块的 loader 是基于这个块的 lang 特性、块的标签名以及 webpack 配置进行匹配的。
如果指定了一个 lang 特性,则这个自定义块将会作为一个带有该 lang 扩展名的文件进行匹配。
你也可以使用 resourceQuery 来为一个没有 lang 的自定义块匹配一条规则。例如为了匹配自定义块 <foo>:
{
module: {
rules: [
{
resourceQuery: /blockType=foo/,
loader: 'loader-to-use'
}
]
}
}
如果找到了一个自定义块的匹配规则,它将会被处理,否则该自定义块会被默默忽略。
此外,如果这个自定义块被所有匹配的 loader 处理之后导出一个函数作为最终结果,则这个 *.vue 文件的组件会作为一个参数被这个函数调用。
3. 自定义块的例子
这里有一个向组件内注入 <docs> 自定义块的示例,且它是在运行时可用的。
为了注入自定义块的内容,撰写一个自定义 loader:
module.exports = function (source, map) {
this.callback(
null,
`export default function (Component) {
Component.options.__docs = ${
JSON.stringify(source)
}
}`,
map
)
}
现在我们将会配置 webpack 来使用为 <docs> 自定义块撰写的自定义 loader。
// wepback.config.js
module.exports = {
module: {
rules: [
{
resourceQuery: /blockType=docs/,
loader: require.resolve('./docs-loader.js')
}
]
}
}
现在可以在运行时访问被导入组件的 <docs> 块内容了。
<!-- ComponentB.vue -->
<template>
<div>Hello</div>
</template>
<docs>
This is the documentation for component B.
</docs>
<!-- ComponentA.vue -->
<template>
<div>
<ComponentB/>
<p>{{ docs }}</p>
</div>
</template>
<script>
import ComponentB from './ComponentB.vue';
export default {
components: { ComponentB },
data () {
return {
docs: ComponentB.__docs
}
}
}
</script>