下面是Vue高级组件之函数式组件的使用场景与源码分析的详细攻略:
什么是函数式组件?
函数式组件在Vue2.3版本中引入的新特性,可以提高组件的性能和减少不必要的组件实例化。它是一种纯函数,接受一个props对象并返回渲染的虚拟DOM。它没有状态(即数据驱动),也没有实例,所以没有生命周期函数,仅仅是一个接收props并返回渲染vnode的函数。使用函数式组件可以减少不必要的组件实例化,避免组件状态带来的性能开销,同时减少内部无状态组件的渲染次数。
下面是一个函数式组件的例子:
<template functional>
<div class="functional-component">
{{props.text}}
</div>
</template>
函数式组件的使用场景
函数式组件通常用于以下场景:
- 只需要展示数据,不需要进行交互的组件。
- 高阶组件中的无状态组件。
- 当父组件需要多次使用某个组件时,可以把这个组件改成函数式组件,减少组件实例化次数。
通过使用函数式组件,可以大大提高Vue应用的整体性能。
函数式组件的源码分析
函数式组件在Vue源码中的实现过程如下:
- 创建函数式组件的VNode节点(函数式组件没有组件实例,因此没有VNode子树)。
- 获取函数式组件名,并将其添加到VNode的
fnContext
属性中。 - 将组件的props和children绑定到VNode的
data
属性中。 - 返回VNode作为函数式组件的渲染结果。由于函数式组件没有实例,因此不需要调用
_render
方法。
下面是一个更详细的源码分析:
// src/core/vdom/create-component.js
export function createFunctionalComponent (
Ctor: Class<Component>,
propsData: ?Object,
data: ?VNodeData,
contextVm: ?Component,
children: ?Array<VNode>,
tag?: string
): VNode | Array<VNode> {
const props = {}
const propOptions = Ctor.options.props
// 将propsData转成props对象
if (propsData !== undefined) {
for (const key in propOptions) {
props[key] = propsData[key]
}
}
// 为VNode设置组件名和props
const renderContext = new FunctionalRenderContext(props, data, contextVm, children, tag)
const vnode = Ctor.options.render.call(null, renderContext._c, renderContext)
// 设置fnContext属性
vnode.fnContext = contextVm
vnode.fnOptions = Ctor.options
if (data.slot) {
(vnode.data || (vnode.data = {})).slot = data.slot
}
// 将props和children绑定到data属性中
return vnode
}
// src/core/vdom/create-functional-component.js
export class FunctionalRenderContext {
// 构造函数
constructor (
props: any, // props
data: any, // VNodeData
parentVm: Component, // 父组件
children: ?Array<VNode>, // 子节点
tag?: string // 标签名
) {
this.props = props
this.data = data
this.children = children
this.parent = parentVm
this.listeners = {}
this.slots = () => resolveSlots(children, contextVm)
this.scopedSlots = {}
this.slots._ctx = contextVm
this._c = (a, b, c, d) => createElement(contextVm, a, b, c, d, false)
}
}
以上是函数式组件的实现过程,也就是说函数式组件的渲染和普通组件的渲染是有所不同的。
示范1:使用函数式组件进行布局优化
可以使用函数式组件进行布局优化,例如在一个列表中,每个item中有一段固定的文本,这段文本不需要重复渲染,可以使用函数式组件只渲染一次。示例如下:
在列表中使用函数式组件:
<template>
<div>
<ul>
<li v-for="item in list" :key="item.id">
<some-text :text="'固定文本'" />
{{item.text}}
</li>
</ul>
</div>
</template>
<script>
import SomeText from '@/components/SomeText.vue'
export default {
components: {
SomeText
},
data() {
return {
list: [
{id: 1, text: 'item 1'},
{id: 2,text: 'item 2'},
...
]
}
}
}
</script>
函数式组件具体实现:
<template functional>
<div>{{props.text}}</div>
</template>
最终运行结果:整个列表只渲染了一次 <some-text>
组件,减少了渲染次数,提高了性能。
示范2:使用函数式组件进行性能优化
针对高阶组件(HOC)的优化,我们可以使用函数式组件优化,这样通过高阶组件渲染的无状态组件就会不会导致不必要的组件实例化,优化性能。
使用高阶组件:
<template>
<div>
<Button />
</div>
</template>
<script>
import hoc from '@/hoc/Hoc'
export default {
components: {
Button: hoc(Button)
}
}
</script>
高阶组件 HOC:
export default (WrappedComponent) => {
return {
functional: true,
render(h, { data, children }) {
return h(WrappedComponent, data, children)
}
}
}
以上便是 Vue 高级组件之函数式组件的使用场景与源码分析的攻略。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue高级组件之函数式组件的使用场景与源码分析 - Python技术站