你可以把 TSX 的学习和使用分为 三个核心部分

  1. 基础概念与环境配置 (The What & How to Setup)
  2. 核心语法与实践 (The Core Syntax)
  3. 在 Vue 中的特定应用与技巧 (Vue-specific Patterns)

第一部分:基础概念与环境配置

这是什么?

  • TSX = TypeScript + JSX。它本质上是 JavaScript 的一个语法扩展(JSX),并为其提供了 TypeScript 的静态类型检查能力。它允许你在 TypeScript 文件(.tsx)中编写类似 XML/HTML 的代码结构。
  • 它不是浏览器原生支持的。TSX 代码必须经过编译(通常由 Babel 或 Vite 的插件完成),转换成浏览器可以理解的纯 JavaScript(通常是 h() 函数或 React.createElement() 的调用)。

如何配置?
要在 Vue 3 项目中使用 TSX,配置非常简单,特别是使用 Vite 时。

  1. 安装依赖
    通常 Vue 官方脚手架 create-vue 在选择 TypeScript 时会自动安装好。如果没有,请手动安装:

    npm install @vitejs/plugin-vue-jsx -D
    
  2. 配置 vite.config.ts
    确保插件被正确引入和使用。

    // vite.config.ts
    import { defineConfig } from 'vite';
    import vue from '@vitejs/plugin-vue';
    import vueJsx from '@vitejs/plugin-vue-jsx'; // 引入
    
    export default defineConfig({
      plugins: [
        vue(),
        vueJsx(), // 使用
      ],
    });
    
  3. 配置 tsconfig.json
    告诉 TypeScript 编译器如何处理 JSX 语法。

    // tsconfig.json
    {
      "compilerOptions": {
        "jsx": "preserve", // 关键:保留 JSX 语法,交给 Vite/Babel 处理
        "jsxImportSource": "vue" // 关键:指定 JSX 的转换源为 Vue
      }
    }
    

    完成这三步,你的环境就准备好了。


第二部分:核心语法与实践

这是 TSX 的核心用法,涵盖了如何用它来替代 Vue 模板语法中的各种功能。

  1. 基本结构与渲染

    • 文件名:必须是 .tsx
    • 组件定义:使用 defineComponentsetup 函数返回一个渲染函数。
    • 渲染:渲染函数直接返回 JSX 结构。
    import { defineComponent, ref } from 'vue';
    
    export default defineComponent({
      setup() {
        const msg = ref('Hello TSX!');
        return () => <div>{msg.value}</div>;
      }
    });
    
  2. 属性绑定 (Attribute Binding)

    • 静态值class="my-class"
    • 动态值:使用花括号 {},例如 id={dynamicId}
    • classstyle:与 Vue 模板语法一样,支持对象和数组。
  3. 事件处理 (Event Handling)

    • 驼峰命名:事件名使用驼峰式,如 onClick, onMouseOver
    • 绑定函数:直接在花括号中绑定一个函数引用。
    const handleClick = (event: MouseEvent) => {
      console.log('Clicked!', event);
    };
    <button onClick={handleClick}>Click Me</button>
    
  4. 条件渲染 (Conditional Rendering)

    • 完全依赖 JavaScript:没有 v-if 指令。
    • 常用方式:三元运算符、&& 逻辑与、if/else 语句(通常写在渲染函数外部或 IIFE 中)。
    const show = ref(true);
    return () => (
      <div>
        {show.value ? <span>Visible</span> : <span>Hidden</span>}
        {show.value && <span>Also Visible</span>}
      </div>
    );
    
  5. 列表渲染 (List Rendering)

    • 完全依赖 JavaScript:没有 v-for 指令。
    • 使用数组的 .map() 方法
    • 关键:必须为每个列表项提供唯一的 key 属性
    const items = [{ id: 1, text: 'A' }, { id: 2, text: 'B' }];
    return () => (
      <ul>
        {items.map(item => <li key={item.id}>{item.text}</li>)}
      </ul>
    );
    
  6. v-model

    • TSX 直接支持 v-model 指令,用法与模板中一致。
    const text = ref('');
    // 默认 modelValue
    <input v-model={text.value} />
    // 具名 model
    <MyComponent v-model:title={text.value} />
    

第三部分:在 Vue 中的特定应用与技巧

这部分内容展示了 TSX 在 Vue 生态中的高级用法和最佳实践。

  1. Props 的类型定义

    • 这是 TSX 相对于模板语法的最大优势之一。
    • 使用 defineComponentprops 选项,结合 PropType 来定义复杂类型。
    import { defineComponent, type PropType } from 'vue';
    
    interface User {
      id: number;
      name: string;
    }
    
    export default defineComponent({
      props: {
        user: {
          type: Object as PropType<User>,
          required: true
        }
      },
      setup(props) {
        // props.user 会有完整的 User 类型提示
        return () => <div>{props.user.name}</div>;
      }
    });
    
  2. Slots 的使用

    • setup 函数的第二个参数 context 中包含 slots 对象。
    • slots.default() 调用默认插槽,slots.namedSlot() 调用具名插槽。
    • 在父组件中传递插槽时,使用一个对象,key 是插槽名,value 是一个返回 JSX 的函数。
    // 子组件 Card.tsx
    setup(props, { slots }) {
      return () => (
        <div class="card">
          <header>{slots.header ? slots.header() : 'Default Header'}</header>
          <main>{slots.default ? slots.default() : null}</main>
        </div>
      );
    }
    
    // 父组件使用
    import Card from './Card';
    <Card>
      {{
        header: () => <h2>My Card Title</h2>,
        default: () => <p>Content goes here.</p>
      }}
    </Card>
    
  3. 函数式组件 (Functional Components)

    • 对于没有自身状态的纯展示组件,可以直接定义一个接收 propsslots 的函数。
    import type { FunctionalComponent } from 'vue';
    
    interface GreetingProps {
      name: string;
    }
    
    const Greeting: FunctionalComponent<GreetingProps> = (props, { slots }) => {
      return <h1>Hello, {props.name}</h1>;
    };
    
    export default Greeting;
    
  4. 高阶组件 (Higher-Order Components - HOC)

    • 由于 TSX 的本质是 JavaScript,你可以非常方便地使用 HOC 模式(一个接收组件作为参数并返回新组件的函数)来复用逻辑。

总结:如何使用 TSX

  1. 配置环境:确保 Vite/Vue CLI 和 tsconfig 配置正确。
  2. 创建 .tsx 文件:使用 defineComponent 作为起点。
  3. 编写 JSX:在 setup 返回的渲染函数中编写 UI 结构。
  4. 拥抱 JavaScript:用 JS 的原生语法(三元、&&.map())替代模板指令(v-if, v-for)。
  5. 享受类型安全:为 Props、事件等提供精确的 TypeScript 类型,获得无与伦比的开发体验。

最佳实践:在项目中可以将 SFC (.vue 文件) 和 TSX 组件混合使用。对于 UI 结构固定、逻辑简单的组件,SFC 更直观;对于需要大量编程逻辑、动态性极强的组件(如图表、动态表单、可渲染函数组件等),TSX 是一个更强大、更灵活的选择。

更多推荐