首先需要安装编译支持和 vite 支持插件
## babel 基础插件
yarn add @vue/babel-plugin-jsx -D
## 项目用 vite 构建的就需要按照这个
yarn add @vitejs/plugin-vue-jsx -D
使用插件
- 按照 babel-plugin-jsx 的指引在 babel
配置项中启用插件:
{
"plugins": ["@vue/babel-plugin-jsx"]
}
- 按照 @vitejs/plugin-vue-jsx 的指引在 vite.config.js 中启用插件
import vueJsx from '@vitejs/plugin-vue-jsx'
export default {
plugins: [
vueJsx({
// options are passed on to @vue/babel-plugin-jsx
})
]
}
tsconfig.json 配置项添加
tsconfig.json 文件的配置项比较灵活,可以参考 TypeScript 的配置文档,
也可以直接根据 Vue 里面使用 TS 的官方指引 来配置。
使用 tsc --init
可以快速初始化配置。
这里我个人配的是这样:
{
"compilerOptions": {
"module": "ES6",
"target": "ES6",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"jsx": "preserve",
"isolatedModules": true,
"strict": true,
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
}
},
"include": [...]
}
Vue 中的 TSX 和 JSX 与渲染函数的转换关系:
参考:
- Vue 渲染函数 & JSX
https://staging-cn.vuejs.org/guide/extras/render-function.html - babel 编译转换说明
https://github.com/vuejs/babel-plugin-jsx/blob/dev/packages/babel-plugin-jsx/README-zh_CN.md - Vue 渲染函数 API
https://staging-cn.vuejs.org/api/render-function.html#h - Vue 渲染机制
https://staging-cn.vuejs.org/guide/extras/rendering-mechanism.html#virtual-dom
组件代码编写模式
单文件组件(SFC) 模式
参考:
- Vue 单文件中使用 TS
https://staging-cn.vuejs.org/guide/extras/render-function.html#passing-slots
示例一:
<script setup lang="tsx">
import { ref } from "vue"
const message: String = "Hello world"
const count = ref(0)
const inc = () => count.value++
</script>
<template>
<div @click.self="inc">
{{ message }}
{{ count }}
</div>
</template>
示例二:
<script lang="tsx">
import { defineComponent, ref, withModifiers } from "vue"
export default defineComponent({
setup(props) {
const message: String = "Hello world"
const count = ref(0)
const inc = () => count.value++
return () => (
<div onClick={withModifiers(inc, ["self"])}>
{message}
{count.value}
</div>
)
}
})
</script>
TSX 代码编写模式
参考:
- babel 文档示例
https://github.com/vuejs/babel-plugin-jsx/blob/dev/packages/babel-plugin-jsx/README-zh_CN.md - Vue 官网示例
https://staging-cn.vuejs.org/guide/extras/render-function.html#passing-slots
示例一:
import { defineComponent } from "vue"
const A = (props, { slots }) => (
<>
<h1>{slots.default ? slots.default() : 'foo'}</h1>
<h2>{slots.bar?.()}</h2>
</>
);
export default defineComponent({
props: {
messages: String
},
setup(props) {
const slots = {
default: () => <div>A</div>,
bar: () => <span>C</span>,
}
return () => (
<A v-slots={slots}></A>
)
},
})
示例二:
import { defineComponent, ref, withModifiers } from "vue"
export default defineComponent({
setup(props) {
const count = ref(0)
const inc = () => count.value++
return () => (
<div onClick={withModifiers(inc, ["self"])}>
Hello world
{count.value}
</div>
)
}
})
TSX 使用插槽以及作用域插槽
示例一:
main.ts
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
App.vue
<script lang="tsx" setup>
import MainComponent from './components/MainComponent';
</script>
<template>
<MainComponent />
</template>
MainComponent.tsx
import { defineComponent } from "vue";
import TestComponent from "./TestComponent";
export default defineComponent({
setup() {
return () => (
<>
<TestComponent
v-slots={{
default: (str: string, idx: number) => {
console.log(str, idx);
return `hello ${str} ${idx}`;
},
header: () => "世界如此美丽",
}}
/>
<TestComponent>
{{
default: (str: string, idx: number) => {
console.log(str, idx);
return `hello ${str} ${idx + 1}`;
},
header: () => "世界如此美丽",
}}
</TestComponent>
</>
)
}
})
TestComponent.tsx
import { defineComponent, SetupContext } from "vue";
export default defineComponent({
setup(props, ctx: SetupContext) {
const data = "world";
console.log(ctx);
return () => (
<>
<p>
{ ctx.slots.header!() }
</p>
<p>
{ctx.slots.default!(data, 1)}
</p>
</>
)
}
})
示例二:
main.ts
import { createApp } from 'vue'
// import App from './App.vue'
import MainComponent from './components/MainComponent';
createApp(MainComponent).mount('#app')
效果: