Vue高阶组件在实际项目中有着广泛的应用场景,通过函数式组件源码分析可以更深入地了解其实现原理,在Vue的生态系统中,高阶组件的灵活运用能够帮助开发者更高效地管理组件逻辑和状态,提升开发效率和代码复用性。通过深入分析函数式组件的源码,我们可以更好地理解其内部工作原理,为我们在项目中的实际应用提供更多的启发和指导。
Vue提供了一种可以让组件变为无状态、无实例的函数化组件。从原理上说,一般子组件都会经过实例化的过程,而单纯的函数组件并没有这个过程,它可以简单理解为一个中间层,只处理数据,不创建实例,也是由于这个行为,它的渲染开销会低很多。实际的应用场景是,当我们需要在多个组件中选择一个来代为渲染。或者在将children,props,data等数据传递给子组件前进行数据处理时,我们都可以用函数式组件来完成,它本质上也是对组件的一个外部包装。
使用场景定义两个组件对象,test1,test2
var test1 = {props: ['msg'],render: function (createElement, context) { return createElement('h1', this.msg)}}var test2 = {props: ['msg'],render: function (createElement, context) { return createElement('h2', this.msg)}}
定义一个函数式组件,它会根据计算结果选择其中一个组件进行选项
Vue.component('test3', {// 函数式组件的标志 functional设置为truefunctional: true,props: ['msg'],render: function (createElement, context) { var get = function() { return test1 } return createElement(get(), context)}})
函数式组件的使用
<test3 :msg="msg" id="test"></test3>new Vue({el: '#app',data: { msg: 'test'}})
最终渲染的结果为:
<h2>test</h2>源码分析
函数式组件会在组件的对象定义中,将functional属性设置为true,这个属性是区别普通组件和函数式组件的关键。同样的在遇到子组件占位符时,会进入createComponent进行子组件Vnode的创建。由于functional属性的存在,代码会进入函数式组件的分支中,并返回createFunctionalComponent调用的结果。 注意,执行完createFunctionalComponent后,后续创建子Vnode的逻辑不会执行,这也是之后在创建真实节点过程中不会有子Vnode去实例化子组件的原因。(无实例)
function createComponent(){ ··· if (isTrue(Ctor.options.functional)) { return createFunctionalComponent(Ctor, propsData, data, context, children) }}
createFunctionalComponent方法会对传入的数据进行检测和合并,实例化FunctionalRenderContext。最终调用函数式组件自定义的render方法执行渲染过程。
function createFunctionalComponent( Ctor, // 函数式组件构造器 propsData, // 传入组件的props data, // 占位符组件传入的attr属性 context, // vue实例 children// 子节点){ // 数据检测合并 var options = Ctor.options; var props = {}; var propOptions = options.props; if (isDef(propOptions)) { for (var key in propOptions) { props[key] = validateProp(key, propOptions, propsData || emptyObject); } } else { // 合并attrs if (isDef(data.attrs)) { mergeProps(props, data.attrs); } // 合并props if (isDef(data.props)) { mergeProps(props, data.props); } } var renderContext = new FunctionalRenderContext(data,props,children,contextVm,Ctor); // 调用函数式组件中自定的render函数 var vnode = options.render.call(null, renderContext._c, renderContext)}
而FunctionalRenderContext这个类最终的目的是定义一个和真实组件渲染不同的render方法。
function FunctionalRenderContext() { // 省略其他逻辑 this._c = function (a, b, c, d) { return createElement(contextVm, a, b, c, d, needNormalization); };}
执行render函数的过程,又会递归调用createElement的方法,这时的组件已经是真实的组件,开始执行正常的组件挂载流程。
问题:为什么函数式组件需要定义一个不同的createElement方法?- 函数式组件createElement和以往唯一的不同是,最后一个参数的不同。之前章节有说到,createElement会根据最后一个参数决定是否对子Vnode进行拍平,一般情况下,children编译生成结果都是Vnode类型,只有函数式组件比较特殊,它可以返回一个数组,这时候拍平就是有必要的。我们看下面的例子:
Vue.component('test', { functional: true, render: function (createElement, context) { return context.slots().default } }) <test> <p>slot1</p> <p>slot</p> </test>
此时函数式组件test的render函数返回的是两个slot的Vnode,它是以数组的形式存在的,这就是需要拍平的场景。
总结到此这篇关于vue高阶组件应用场景的文章就介绍到这了,更多相关Vue高级组件之函数式组件内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
以上是关于vue高阶组件应用场景的全部内容,如果有遇到相同问题的用户,可以参考本文中介绍的步骤来进行修复,希望对大家有所帮助。