阅读 138

Vue3 函数式组件的开发方式

声明式组件和服务式组件

无论是使用第三方组件库,还是自己封装组件,有一类组件有些与众不同,那就是函数式/服务式组件,比如 Message 消息组件、Notification 通知组件、Loading 加载组件等等。

以 ElementPlus 组件库为例,大部分组件都是声明式的,比如:

<el-button type="primary" @click="handleClick">点击</el-button>  <el-input v-model="username" /> 复制代码

声明式组件和函数式组件,最大的不同就是渲染组件的方式,前者是声明式,后者是需要通过调用 API 的方式,去渲染组件,比如:

import { ElMessage } from 'element-plus'  // 通常是在某个交互完成时触发 const handleClick = () => {   ElMessage.success('成功')   // ElMessage.error('错误') } 复制代码

再有一点就是,函数式组件通常都挂载到 body 上。而且,一般全局只维护一个或多个实例,比如 Notification 组件,可能存在多个通知消息,比如 Confirm 组件,通常全局只会渲染一个确认框。

函数式组件的实现方式

对于声明式组件,大家都非常熟悉,就是写一个 .vue 文件,在里面写 template、script 和 style,哪里需要,就在哪里导入。

而对于函数式组件,在封装时除了要写 .vue (甚至可以不写,直接写虚拟DOM),还要多一个手动渲染和卸载的步骤,就要用到 render 函数和 h 函数了。

h 函数

在 Vue3 中,h 函数是一个重载函数,支持多种调用方式,但在内部会处理为符合 createVNode 函数的入参,然后交给 createVNode 来创建虚拟 DOM。

因为创建虚拟节点有多种不同的情况,比如传入标签名和属性,就会创建一个标签的虚拟节点,比如传入组件名和属性,创建一个组件的虚拟节点。createVNode 这个名字太长了,所以使用 h 来代替它,h 是 hyperscript 的简写。而且,createVNode 在创建 VNode 时还可以做一些性能优化的处理。

import { h } from 'vue'  // 使用 h 创建普通标签的 vnode h('div', 'hello')  // 使用 h 创建组件的 vnode h(comp, {     // 组件的属性     title: '测试' }) 复制代码

创建组件的虚拟 DOM 时,就相当于:

<comp title="测试"> 复制代码

render 函数

Vue3 支持用户自定义渲染器,方便使用者实现自己需要的渲染逻辑。同时它也提供了一个默认的渲染器,只能在浏览器平台使用。

从 vue 中导入的 render 函数,就是是 vue 提供的默认渲染器的渲染方法。它接收标签或者组件的虚拟 DOM,将其渲染为真实 DOM,并挂载到一个指定的父节点。

import { render, h } from 'vue'  render(h('div', 'hello'), document.body) 复制代码

当第一个参数为 null 时,相当于从父节点上移除此组件。

render(null, document.body) 复制代码

示例:Message 组件

以 Message 组件为例,先照常写一个普通的组件:

// message.vue  <template>   <transition name="fade" @after-leave="destroy">     <div v-show="isVisable">         {{ message }}     </div>   </transition> </template>  <script setup> import { ref, onMounted } from 'vue'  const props = defineProps({    // 消息内容   message: {     type: String,     required: true   },        // 停留时长   duration: Number,        // 关闭时的回调   destroy: Function })  // 控制显示处理 const isVisable = ref(false)  onMounted(() => {   isVisable.value = true   setTimeout(() => {     isVisable.value = false   }, props.duration) })      </script>  <style lang="scss" scoped> .fade-enter-active, .fade-leave-active {   transition: all 0.5s; }  .fade-enter-from, .fade-leave-to {   opacity: 0;   transform: translate3d(-50%, -100%); } </style> 复制代码

再写渲染组件的方法:

// message.js  import { render, h } from 'vue' import messageComponent from './message.vue'  export const message = (message, duration = 3000) => {   const handleDestroy = () => {     // 从 body 上移除组件     render(null, document.body)   }    // 使用 h 函数创建 vnode   const vnode = h(messageComponent, {     message,     duration,     destroy: handleDestroy   })   // 使用 render 函数将 vnode 渲染为真实DOM并挂载到 body 上   render(vnode, document.body) } 复制代码

小结

本文介绍了如何在 Vue3 中封装一个函数式的组件,和封装普通组件有几点不同之处:

  1. 组件通过 API 调用渲染

  2. 要用到 vue 的 render 和 h 函数,可以由用户控制组件渲染的时机

  3. 往往挂载到 body 节点上

对于 render 和 h 函数,属于偏底层的 API,可以参看 Vue 官方文档或者源码,做一个更深入的了解。


作者:昆吾kw
链接:https://juejin.cn/post/7170511660648988685


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐