在Vue3中使用JSX/TSX

799 阅读2分钟

前言

公司之前用Vue2写的老项目需要升级到Vue3,由于本人React写的比较多,对JSX/TSX(以下统称为JSX)比较喜欢,所以在项目新功能开发时,抱着试一试的心态引入了JSX,体验下来还是能满足90%左右的需求,这篇文章就给大家来分享一下在Vue3项目中使用JSX的一些注意事项和心得体会。

环境介绍

项目主要环境及版本:

packageversion
vite@3.2.3
vue@3.2.41
@vitejs/plugin-vue@3.2.0
@vitejs/plugin-vue-jsx@2.1.1

开始写一个JSX

在本人一段时间的体验下来,对开发来说体验感最好方式是.vue文件的SFC模式,将lang改为tsx(可能需要配置一下tsconfig)。这种模式的好处在于可以在编写JSX的同时享受Vue的scoped-css提供的编写。

<script lang="tsx">
export default defineComponent({
    // ...
})
</script>

<style scoped>
// 这里可以写样式
</style>

但是在这之前还是先聊一下JSX和Vue配合的几种方式:

.jsx + defineComponent

这种方式比较简单,就是采用defineComponent函数创建一个组件,使用setup方法返回组件的DOM结构,这里就不多说了,我编写了一个代码片段,贴出来给大家可以直接在vscode中使用。

{
  "vue3 setup template": {
    "prefix": "vue-setup",
    "body": [
      "import { defineComponent, onMounted, ref, reactive } from 'vue';\n",
      "export interface ${TM_FILENAME_BASE}Props {}\n",
      "export default defineComponent({",
      "\tprops: [],",
      "\tsetup(props: ${TM_FILENAME_BASE}Props, { emit }) {",
      "\t\tonMounted(() => {",
      "\t\t\t// ...",
      "\t\t})",
      "\t\treturn () => (",
      "\t\t\t<div></div>",
      "\t\t)",
      "\t}",
      "})"
    ]
  }
 }

.jsx + functionalComponent

Vue3是支持函数式组件的,可以在jsx文件中直接默认到处一个函数,返回组件的DOM结构即可,在函数中可以使用Vue3提供的类hooksAPI来创建响应式数据,函数的参数和setup函数的参数是同样的([props, context])。

import {FunctionalComponent} from 'vue'
export interface ComponentProps {
    cotnent: string
}

export default (pros, context) => {
    return <div>{props.content}</div>
} as FunctionalComponent<ComponentProps>

但是函数式组件在vite中并不支持热重载,所以本人也没有深入使用过,若有知道如何配置函数式组件热重载的小伙伴可以告诉我哦。

.vue + defineComponent

这种方式就是我在一开始的时候提到的方式,也是我使用最多的方式之一,好处在上文已经说过了,这里直接贴出我的vscode代码片段

{
  "tsx setup": {
    "prefix": "setuptsx",
    "body": [
      "<script lang=\"tsx\">",
      "import { defineComponent, onMounted, reactive, ref } from 'vue';\n",
      "export interface ${TM_FILENAME_BASE}Props {}\n",
      "export default defineComponent({",
      "\tprops: [],",
      "\tsetup(props: ${TM_FILENAME_BASE}Props, { emit }) {",
      "\t\tonMounted(() => {",
      "\t\t\t// ...",
      "\t\t})",
      "\t\treturn () => (",
      "\t\t\t<div></div>",
      "\t\t)",
      "\t}",
      "})",
      "</script>"
    ]
  },
}

踩过的坑

这一块内容我会长期更新,大家也可以给我留言,讨论一下jsx和vue配合产生的一些稀奇古怪的issues

1. 组件中返回一个HTML结构会渲染成[Object object]

举个例子:


const renderDiv =  () => {
    return <div>abc</div>
}

export default defineComponent({
    setup() {
        return <div>{renderDiv()}</div>
    }
})

渲染出的HTML会变成

<div>
<!-- [Object object] -->
</div>