在现有项目里面添加 TSX 并编写组件过程记录

407 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

首先需要安装编译支持和 vite 支持插件

## babel 基础插件
yarn add @vue/babel-plugin-jsx -D

## 项目用 vite 构建的就需要按照这个
yarn add @vitejs/plugin-vue-jsx -D 

 

使用插件

  1. 按照 babel-plugin-jsx 的指引在 babel 配置项中启用插件:
{
  "plugins": ["@vue/babel-plugin-jsx"]
}
  1. 按照 @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 与渲染函数的转换关系:

参考:

 

组件代码编写模式

单文件组件(SFC) 模式

参考:

示例一:

<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 }}
        &nbsp;
        {{ 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}
                &nbsp;
                {count.value}
            </div>
        )
    }
})
</script>

 

TSX 代码编写模式

参考:

示例一:

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 &nbsp;
                {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')

效果:

2022-12-15 11-01-55.png