Vue3多组件的N种编写方式

 更新时间:2024年07月24日 08:47:32   作者:pany  
Vue 本身以及周边生态在设计语法糖上几乎没让我失望过,包括本次亮相的 Vue Vine,它的出现引起了我对 Vue3 组件编写方式的好奇,以及哪一种方式更接近「最佳实践」?下面让我来为大家一一道来

Vue 本身以及周边生态在设计语法糖上几乎没让我失望过,包括本次在 VueConf 2024 深圳盛会上正式亮相的 Vue Vine。

它的出现引起了我对 Vue3 组件编写方式的好奇,以及哪一种方式更接近「最佳实践」?

那么 Vue Vine 究竟是一个什么有意思的工具?以及与这个工具类似的其他工具都有哪些?它们分别对应的场景是什么?该如何选择?

下面让我来为大家一一道来:

SFC 单文件组件

我们在用编写代码时,经常是会出现重复的代码,就比如:

<template>
  <dialog v-if="showInDialog">
    <!-- 代码片段 -->
  </dialog>
  <div v-else>
    <!-- 代码片段 -->
  </div>
</template>

如果我们不想将「代码片段」这部分重复的写两遍该怎么办?

这时候,我们往往会将这个代码片段拎出来放在一个新建的 .vue 子组件中:

<!-- 父组件 -->
<template>
  <dialog v-if="showInDialog">
    <Content />
  </dialog>
  <div v-else>
    <Content />
  </div>
</template>

<!-- 子组件 Content.vue -->
<template>
  <!-- 代码片段 -->
</template>

这本身是 Vue 官方默认的一种组件化开发方式,也就是 SFC 单文件组件。

但是在某些情况下,我们可能并不想将这部分「代码片段」拆分成独立的单文件,比如「代码片段」非常的简单的时候,又或者父组件代码量并不多的时候...

并且强行拆分带来的一系列繁琐操作有时也挺烦人,这时候我们就得找一些方案来解决这种单文件组件解决不了的情况。

多模板方案

多模板方案强调的是在一个单文件组件中提取出能复用的模板代码,换句话说就是提取出公共的 HTML 代��。

createReusableTemplate

VueUse 是一个提供了非常多实用的 Vue3 组合式函数(Composables)的工具库,其中便提供了一个创建可重用模板的 createReusableTemplate 方法,文档链接是https://vueuse.org/core/createReusableTemplate

使用方式非常简单:

<script setup>
import { createReusableTemplate } from '@vueuse/core'

const [DefineTemplate, ReuseTemplate] = createReusableTemplate()
</script>

<template>
  <DefineTemplate>
    <!-- 代码片段 -->
  </DefineTemplate>

  <dialog v-if="showInDialog">
    <ReuseTemplate />
  </dialog>
  <div v-else>
    <ReuseTemplate />
  </div>
</template>

用导入的 DefineTemplate 组件注册模板(注意此时不会渲染内容),然后再用 ReuseTemplate 组件来渲染刚才注册的模板(注意 DefineTemplate 必须在 ReuseTemplate 之前使用)即可。

namedTemplate

Vue Macros 像魔法一样,能让你在 Vue3 项目中体验到更多超前的语法糖。并且它还是一块 Vue 语法的试验田,里面诸多的语法都有机会被 Vue 官方收录!

它提供了一个命名模板 namedTemplate 特性,文档链接是 https://vue-macros.dev/zh-CN/features/named-template.html

使用方式如下:

<script setup>
const showInDialog = ref(false)
</script>

<template name="reusable">
  <!-- 代码片段 -->
</template>

<template>
  <template v-if="showInDialog">
    <dialog>
      <template is="reusable" />
    </dialog>
  </template>
  <template v-else>
    <div>
      <template is="reusable" />
    </div>
  </template>
</template>

多组件(无状态)方案

多组件(无状态)方案强调的是在一个文件中定义单个有状态组件 + 多个无状态组件

JSX

JSX 是多组件实践中最常见的一个方案,霸榜了「多组件(无状态)方案」,并且 JSX 方案中写法非常多,涉及到有状态的「组件」和无状态的「函数组件」的知识。

我这里挑选三个常见的方案:defineComponent renderdefineRendersetupSFC,其他写法并不主流,我们就不在这里提及了。

defineComponent render

这是 Vue3 中最朴实无华的使用 JSX 的方式!属于 Vue3 + JSX 梦开始的地方

import { defineComponent, ref } from "vue"

export default defineComponent({
  setup() {
    // 使用 ref 创建一个响应式变量来控制显示状态
    const showInDialog = ref(false)
    // 声明一个无状态函数组件 Content 用于渲染代码片段
    function Content() {
      return <div>代码片段</div>
    }
    // 返回 render 函数
    return () => (
      <div>
        {showInDialog.value ? (
          <dialog>
            <Content />
          </dialog>
        ) : (
          <div>
            <Content />
          </div>
        )}
      </div>
    )
  }
})

defineComponent 方法用于定义组件,在 setup 方法内部我们可以利用「函数组件」来定义一些需要复用的「无状态组件」,最后直接返回 render 函数即可。

本质上就是「defineComponent + render + 无状态函数组件 + JSX」的配合使用

defineRender

而 defineRender 则可以看作是 defineComponent render 的升级版,它也是 Vue Macros 提供的方法。

使用 defineRender 可以直接在 <script setup> 中定义渲染函数:

<script setup lang="jsx">
// 使用 ref 创建一个响应式变量来控制显示状态
const showInDialog = ref(false)
// 声明一个无状态函数组件 Content 用于渲染代码片段
function Content() {
  return <div>代码片段</div>
}

defineRender(
  <div>
    {showInDialog.value ? (
      <dialog>
        <Content />
      </dialog>
    ) : (
      <div>
        <Content />
      </div>
    )}
  </div>
)
</script>

这种方式虽然告别了 defineComponentOptions API 使得代码更加轻量,但是在 .vue 中写 jsx 还是不够优雅。

于是又有了关于它的升级版 setupSFC

setupSFC

setupSFC 是我比较喜欢的在 Vue3 中编写 JSX 组件的方案之一(它依旧是 Vue Macros 提供的方法)。

我们开发时需要定义后缀为 .setup.tsx / .setup.jsx 的文件:

// 使用 ref 创建一个响应式变量来控制显示状态
const showInDialog = ref(false)
// 声明一个无状态函数组件 Content 用于渲染代码片段
function Content() {
  return <div>代码片段</div>
}

export default () => (
  <div>
    {showInDialog.value ? (
      <dialog>
        <Content />
      </dialog>
    ) : (
      <div>
        <Content />
      </div>
    )}
  </div>
)

告别了 defineComponentOptions API,将 setupjsx 完美的融合。

多组件(有状态)方案

多组件(有状态)方案强调的是在一个文件中定义多个有状态组件

JSX

没错,JSX 霸榜了「多组件(无状态)方案」后,也活跃在「多组件(有状态)方案」中!

defineComponent render

其实,我们把前文提到的「defineComponent render」多定义几遍,也就是本方案了。

import { defineComponent, ref } from "vue"

// 子组件
const Content = defineComponent({
  setup() {
    return () => <div>代码片段</div>
  }
})

// 父组件
const App = defineComponent({
  setup() {
    const showInDialog = ref(false)

    return () => (
      <div>
        {showInDialog.value ? (
          <dialog>
            <Content />
          </dialog>
        ) : (
          <div>
            <Content />
          </div>
        )}
      </div>
    )
  }
})

export default App

在一个文件中堆砌 defineComponent 即可,这个形式类似于 React 中的 “类组件”

setupComponent

既然 “类组件” 有了,那么有没有 “有状态的函数组件” 呢?

于是 Vue Macros 它又又又提供了一个非常酷的语法 setupComponent,可以在 .jsx 文件中书写多个 “有状态函数组件”,这也是我最喜欢的在 Vue3 中编写 JSX 组件的方案。

// 子组件
const Content = defineSetupComponent(() => {
  return <div>代码片段</div>
})

// 父组件
const App = defineSetupComponent(() => {
  const showInDialog = ref(false)

  return (
    <div>
      {showInDialog.value ? (
        <dialog>
          <Content />
        </dialog>
      ) : (
        <div>
          <Content />
        </div>
      )}
    </div>
  )
})

export default App

Vue Vine

有没有发现,文章到目前为止的多组件方案中,全是基于 JSX 的。那有没有一种既用模板又能支持多组件的方案呢?

那就得说说 Vue Vine 了。

值得注意的是 Vine 仅支持 Vue3 + Vite + TS,然后我们建立一个 .vine.ts 文件:

// 子组件
function Content() {
  return vine`<div>代码片段</div>`
}

// 父组件
function App() {
  const showInDialog = ref(false)

  return vine`
    <div>
      <template v-if="showInDialog">
        <dialog>
          <Content />
        </dialog>
      </template>
      <template v-else>
        <div>
          <Content />
        </div>
      </template>
    </div>
  `
}

export default App

一个函数就是一个组件,然后用 vine 标记的模板字符串声明组件模板。

这种书写方式和刚刚提到的 setupComponent 非常相似,都属于 “有状态的函数组件”,但区别就是一个返回 JSX,一个返回模板,模板的优势就在于 Vue 对其有编译时优化。

总结

  • 大多数情况下,依旧首选 SFC 单文件组件方案就行
  • 针对模板的复用,我虽然更喜欢 Vue Macros 提供的 namedTemplate 方案,但是鉴于目前的稳定性,还是建议采用 VueUse 提供的 createReusableTemplate 方案
  • 针对多组件情景,现阶段还是建议首选 JSX 方案下稳妥的 defineComponent render 方案。喜欢尝鲜的开发者可以大胆尝试 Vue Macros 提供的 setupComponent 或选择 Vue Vine

End

以上就是Vue3多组件的N种编写方式的详细内容,更多关于Vue3多组件编写方式的资料请关注脚本之家其它相关文章!

相关文章

  • vue 获取到数据但却渲染不到页面上的解决方法

    vue 获取到数据但却渲染不到页面上的解决方法

    这篇文章主要介绍了vue 获取到数据但却渲染不到页面上的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • vue实现两个区域滚动条同步滚动

    vue实现两个区域滚动条同步滚动

    这篇文章主要为大家详细介绍了vue实现两个区域滚动条同步滚动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • Webpack打包图片-js-vue 案例解析

    Webpack打包图片-js-vue 案例解析

    在开发中我们会有各种各样的模块依赖,这些模块可能来自于自己编写的代码,也可能来自第三方库,本文给大家介绍Webpack打包图片-js-vue的相关知识,感兴趣的朋友跟随小编一起看看吧
    2023-11-11
  • VUE2实现事件驱动弹窗示例

    VUE2实现事件驱动弹窗示例

    本篇文章主要介绍了VUE2实现事件驱动弹窗示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Vue3源码解读computed和watch

    Vue3源码解读computed和watch

    这篇文章主要为大家介绍了Vue3中的computed和watch源码解读分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Vue+ElementUI容器无法铺满网页的问题解决

    Vue+ElementUI容器无法铺满网页的问题解决

    这篇文章主要介绍了Vue+ElementUI容器无法铺满网页的问题解决,文章通过图文结合的方式给大家讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-08-08
  • 解决Vue动态加载本地图片问题

    解决Vue动态加载本地图片问题

    这篇文章主要介绍了Vue如何动态加载本地图片的相关知识,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • 如何解决el-checkbox选中状态更改问题

    如何解决el-checkbox选中状态更改问题

    这篇文章主要介绍了如何解决el-checkbox选中状态更改问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • 配置一个vue3.0项目的完整步骤

    配置一个vue3.0项目的完整步骤

    这篇文章主要介绍了配置一个vue3.0项目的完整步骤,从0开始配置一个vue项目,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-04-04
  • Vue实现表格中对数据进行转换、处理的方法

    Vue实现表格中对数据进行转换、处理的方法

    这篇文章主要介绍了Vue实现表格中对数据进行转换、处理的方法,需要的朋友可以参考下
    2018-09-09

最新评论