Vue高级组件之函数式组件的使用场景与源码分析

 更新时间:2021年11月09日 15:36:05   作者:AirStar  
Vue提供了一种称为函数式组件的组件类型,用来定义那些没有响应数据,也不需要有任何生命周期的场景,它只接受一些props来显示组件,下面这篇文章主要给大家介绍了关于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设置为true
functional: 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高级组件之函数式组件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue3中的createApp分析

    vue3中的createApp分析

    这篇文章主要介绍了vue3中的createApp分析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Vue编译器optimize源码分析

    Vue编译器optimize源码分析

    这篇文章主要为大家介绍了Vue 编译器optimize源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • vue+flv.js+SpringBoot+websocket实现视频监控与回放功能

    vue+flv.js+SpringBoot+websocket实现视频监控与回放功能

    vue+springboot的项目,需要在页面展示出海康的硬盘录像机连接的摄像头的实时监控画面以及回放功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2022-02-02
  • vite+vue3+element-plus项目搭建的方法步骤

    vite+vue3+element-plus项目搭建的方法步骤

    因为vue3出了一段时间了,element也出了基于vue3.x版本的element-plus,vite打包听说很快,尝试一下,感兴趣的可以了解一下
    2021-06-06
  • vue中v-model对select的绑定操作

    vue中v-model对select的绑定操作

    这篇文章主要介绍了vue中v-model对select的绑定操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • vue 解决mintui弹窗弹起来,底部页面滚动bug问题

    vue 解决mintui弹窗弹起来,底部页面滚动bug问题

    这篇文章主要介绍了vue 解决mintui弹窗弹起来,底部页面滚动bug问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-11-11
  • 使用Element实现表格表头添加搜索图标和功能

    使用Element实现表格表头添加搜索图标和功能

    这篇文章主要介绍了使用Element实现表格表头添加搜索图标和功能,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • 浅谈vue2 单页面如何设置网页title

    浅谈vue2 单页面如何设置网页title

    这篇文章主要介绍了浅谈vue2 单页面如何设置网页title,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • vue-json-editor json编辑器的使用

    vue-json-editor json编辑器的使用

    本文主要介绍了vue-json-editor json编辑器的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • 使用idea创建vue项目的图文教程

    使用idea创建vue项目的图文教程

    Vue.js是一套构建用户界面的框架,只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合,下面这篇文章主要给大家介绍了关于使用idea创建vue项目的相关资料,需要的朋友可以参考下
    2022-08-08

最新评论