Vue3 函数式组件的开发方式

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

声明式组件和服务式组件

无论是使用第三方组件库还是自己封装组件有一类组件有些与众不同那就是函数式/服务式组件比如 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 官方文档或者源码做一个更深入的了解。

最后

整理了一套《前端大厂面试宝典》包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法一共201道面试题并对每个问题作出了回答和解析。

有需要的小伙伴可以点击文末卡片领取这份文档无偿分享

部分文档展示



文章篇幅有限后面的内容就不一一展示了

有需要的小伙伴可以点下方卡片免费领取

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue