TSX详细说明(vue3方向) 作者:马育民 • 2026-05-19 11:13 • 阅读:10003 # 介绍 Vue3 的 TSX 是 **TypeScript + JSX** 的组件写法,用 JavaScript 生成模板,兼具**类型安全**与**编程灵活性**,适合复杂动态场景,与 React JSX 相似但有 Vue 专属规则。 ### 优点 1. **强类型**:TS 原生支持,减少运行时错误。 2. **高灵活**:直接写 JS 逻辑,复杂动态场景更高效。 3. **全能力**:可使用所有 JS 特性(循环、条件、函数)。 4. **易集成**:与 React 生态兼容,迁移成本低。 ### 缺点 1. **学习曲线**:需熟悉 JSX 与 Vue 规则。 2. **模板可读性**:复杂结构不如 SFC 直观。 3. **样式限制**:无内置 scoped,需额外方案。 4. **生态差异**:Vue 生态以 SFC 为主,部分库适配不足。 ### 适用场景 - ✅ 复杂动态表单/表格 - ✅ 高度定制化组件(如可视化编辑器) - ✅ 泛型/递归组件 - ✅ 团队熟悉 React 技术栈 - ❌ 简单静态页面(优先 SFC) --- # 概念 - **TSX = TypeScript + JSX**:在 `.tsx` 文件或 ` {msg.value}} /> ``` ### 3. 渲染函数(h 函数,底层) ```typescript import { defineComponent, h } from 'vue' export default defineComponent({ setup() { return () => h('div', { class: 'hello' }, [h('h1', 'Hello TSX')]) } }) ``` --- # 语法详解 ### 1. 模板基础 - **标签**:同 HTML,支持原生与自定义组件。 - **表达式**:用 `{}` 包裹,如 `{msg.value}`。 - **片段**:用 `<>` 或 `` 包裹多根节点。 ```typescript return () => ( <> 第一行 第二行 > ) ``` ### 2. 属性与绑定 #### (1)普通属性 ```typescript // 静态 // 动态 ``` #### (2)v-bind(`:`) ```typescript // 单个 // 批量 ``` #### (3)v-on(`@`) ```typescript 点击 // 带参数 handleSubmit('ok')}>提交 ``` ### 3. 指令支持 Vue TSX 支持部分指令,**需注意写法差异**: - ✅ `v-if`/`v-else`:直接用 - ✅ `v-for`:用 `map` 替代 - ✅ `v-show`:直接用 - ❌ `v-model`:需用 `v-model` 或 `modelValue` - ❌ `v-slot`:用 `slots` ```typescript // v-if {isShow.value && 显示} // v-for {list.value.map(item => {item.name})} // v-show 显示 ``` ### 4. Props 与类型 #### (1)defineProps(TS 类型) ```typescript import { defineComponent, defineProps } from 'vue' export default defineComponent({ props: { msg: String, count: { type: Number, default: 0 } }, setup(props) { return () => {props.msg} {props.count} } }) ``` #### (2)泛型 Props(Vue3.3+) ```typescript import { defineComponent } from 'vue' export default defineComponent<{ list: string[] }>((props) => { return () => {props.list.join(',')} }) ``` ### 5. 插槽(Slots) #### (1)默认插槽 ```typescript // 子组件 Child.tsx import { defineComponent } from 'vue' export default defineComponent({ setup(props, { slots }) { return () => {slots.default?.()} } }) // 父组件使用 插槽内容 ``` #### (2)命名插槽 ```typescript // 子组件 return () => ( {slots.header?.()} {slots.default?.()} {slots.footer?.()} ) // 父组件 {{ header: () => 头部, default: () => 内容, footer: () => 底部 }} ``` ### 6. 响应式数据 - **ref**:需用 `.value` 访问 - **reactive**:直接访问 ```typescript import { ref, reactive } from 'vue' export default defineComponent({ setup() { const count = ref(0) const user = reactive({ name: 'Tom' }) return () => ( {count.value} {user.name} ) } }) ``` --- # 高级用法 ### 1. 组件递归 ```typescript // Tree.tsx import { defineComponent } from 'vue' interface TreeNode { name: string children?: TreeNode[] } export default defineComponent({ props: { data: Object as () => TreeNode }, setup(props) { return () => ( {props.data.name} {props.data.children?.map(child => ( ))} ) } }) ``` ### 2. 动态组件 ```typescript import { defineComponent, shallowRef } from 'vue' import ComponentA from './A' import ComponentB from './B' export default defineComponent({ setup() { const current = shallowRef(ComponentA) return () => ( current.value = ComponentB}>切换 ) } }) ``` ### 3. 样式处理 - **内联样式**:对象形式 ```typescript ``` - **CSS 模块**:导入 `.module.css` ```typescript import styles from './box.module.css' ``` - **CSS-in-JS**:使用 `styled-components` 等 --- # 常见问题 ### 1. TSX 中 ref 不生效 - 原因:TSX 不会自动解包,需用 `.value` - 解决:`const count = ref(0)` → `{count.value}` ### 2. 如何使用 v-model ```typescript // 组件 defineProps<{ modelValue: string }>() defineEmits<{ (e: 'update:modelValue', value: string): void }>() // 使用 // 或 emit('update:modelValue', e.target.value)} /> ``` ### 3. 如何配置全局组件 ```typescript // main.ts import { createApp } from 'vue' import App from './App' import MyButton from './MyButton' const app = createApp(App) app.component('MyButton', MyButton) ``` 原文出处:http://www.malaoshi.top/show_1GW3L3QiBIfr.html