在 Vue 中使用 JSX
概述
JSX 就是 JavaScript XML, 是 XML 格式的代码, 但是背后会转换为 JS 代码. 本质是虚拟 DOM 的创建代码. 可以视为语法糖.
在 Vue 中使用 JSX 需要几个步骤:
- 安装必要插件
@vitejs/plugin-vue-jsx
, 配置vite.config.ts
. - 使用
JSX
, 有两个形式:- 直接使用
.tsx
文件 (如同react
). - 使用
.vue
文件, 在其中使用lang="tsx"
的<script>
.
- 直接使用
- 使用
JSX
语法. 是否使用setup
是的使用JSX
的方式略有不同.
也可以使用
lang="js"
, 但不支持类型.
详细步骤
使用 vue@latest
向导会提示安装 jsx
插件, 并做好配置.
如果需要自行安装:
npm install --save-dev @vitejs/plugin-vue-jsx
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
export default defineConfig({
plugins: [
vue(),
vueJsx(), // 使 Vite 支持 JSX
],
});
然后就可以使用 JSX
直接使用 .tsx
文件
直接创建 .tsx
文件, 将其视为一个模块, 直接导出 JSX
即可.
export default () => <div>...</div>
也可以使用
defineComponent
, 但是事实上没必要.export default defineComponent({ render() { return <div>...</div> } })
既然使用
tsx
, 简洁一点最好.
也可以导出 render
函数. 实际上就是一个返回 JSX
的函数. 如果使用对象语法, 那么就必须注明 render
函数名.
export default function render() {
return <div>...</div>
}
或者
export default {
render: () => <div>...</div>
}
暂时还不支持
react
中类语法来创建组件的用法.Vue
是基于函数的组件和模板语法的.
使用 .vue
文件
使用 .vue
文件, 与传统用法类似.
- 使用
<template>
定义模板. 但是在模板中可以直接使用<script>
中定义的组件 (返回JSX
的函数). - 使用
<script lang="tsx">
来编写脚本, 依旧支持setup
语法 (更简洁). - 使用
<style>
来定义样式.
jk 依旧不推荐使用
defineComponent({})
来定义组件.
<template>
<AppComponent></AppComponent>
</template>
<script lang="tsx" setup>
const AppComponent = () => <div></div>
</script>
其实直接使用
.tsx
文件更简洁.
总结一下
使用 JSX
, 核心是使用某个函数返回 JSX
代码, 作为页面模板进行渲染. 但是有函数式与对象式两种形式 (组件).
函数式简洁, 但是对生命周期等模块支持不好.
所以还是推荐使用对象式来定义. 例如:
export default defineComponent({
setup() {
onMounted(() => {
console.log('加载完成')
})
const v = ref<string>()
watch(v, (nV?: string, oV?: string) => {
console.log(`watch: v; oldValue = ${ oV }, newValue = ${ nV }`)
})
return () => (
<div >
<ElInput v-model={v.value}></ElInput>
</div>
)
}
})
使用样式
使用样式分为两种情况
.tsx
模式下, 定义单独的 样式文件. 例如xxx.module.scss
. 推荐模块化的语法..vue
模式下,<style></style>
来定义样式, 也可以使用模块化语法. 使用时<style module="styleName" lang="scss"></style>
.<script>
中使用useCssModule()
方法:const style = useCssModule('styleName')
来引用样式.- 使用模块化后, 不需要考虑
scoped
了.