Vue 项目中选择 TSX 而非传统 .vue 文件的原因分析
作者:代码里的小猫咪
近年来,Vue 项目中使用 TSX(TypeScript JSX)的写法逐渐增多,尤其在 TypeScript 项目中。
1. TSX 与 Vue 的结合背景
1、Vue 3 和 TypeScript
Vue 3 从设计之初便更好地支持 TypeScript。Vue 3 使用了 TypeScript 重写核心,增强了类型推断和类型安全的支持,使得 TypeScript 更适合与 Vue 3 配合使用。
2、组合式 API
Vue 3 推出组合式 API,使代码逻辑更加模块化,也更接近于函数式编程的风格,这让代码结构更贴近 TSX 的写法,方便在 TypeScript 和 JSX 中组织逻辑。
2. 简单的示例 🌰
下面结合几个具体的 🌰 详细说明在 Vue 中使用 TSX 和传统 .vue 文件之间的差异。
2.1 基础组件
假设需要创建一个简单的用户卡片组件,用于显示用户的姓名和年龄。
1、使用 .vue 文件编写
.vue 文件的模板语法非常适合这种简单的展示性组件,因为结构清晰,模板代码直观。
<!-- UserCard.vue --> <template> <div class="user-card"> <p>Name: {{ name }}</p> <p>Age: {{ age }}</p> </div> </template> <script setup lang="ts"> import { defineProps } from 'vue'; const props = defineProps<{ name: string; age: number; }>(); </script>
2、使用 tsx 编写
在 tsx 中写同样的组件,代码结构会略有不同,因为模板和逻辑是统一在一起的:
// UserCard.tsx import { defineComponent } from 'vue'; export default defineComponent({ name: 'UserCard', props: { name: String, age: Number, }, setup(props) { return () => ( <div class="user-card"> <p>Name: {props.name}</p> <p>Age: {props.age}</p> </div> ); }, });
2.2 复杂组件:带插槽和事件处理
插槽和事件处理是 Vue 中常见的功能,在 .vue 文件和 .tsx 文件中实现会略有不同。
1、使用 .vue 文件编写
<!-- Modal.vue --> <template> <div v-if="visible" class="modal"> <div class="modal-content"> <slot></slot> <button @click="close">Close</button> </div> </div> </template> <script setup lang="ts"> import { defineProps, defineEmits } from 'vue'; const props = defineProps<{ visible: boolean }>(); const emit = defineEmits<{ (e: 'close'): void }>(); function close() { emit('close'); } </script> <style scoped> .modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; } .modal-content { background: white; padding: 1rem; margin: auto; } </style>
2、使用 .tsx 编写
tsx 中通过直接传递插槽内容来实现类似的功能。
// Modal.tsx import { defineComponent, ref } from 'vue'; export default defineComponent({ name: 'Modal', props: { visible: Boolean, }, emits: ['close'], setup(props, { emit, slots }) { const close = () => emit('close'); return () => ( props.visible && ( <div class="modal" style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(0, 0, 0, 0.5)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> <div class="modal-content" style={{ background: 'white', padding: '1rem' }}> {slots.default && slots.default()} <button onClick={close}>Close</button> </div> </div> ) ); }, });
展示为:
2.3 使用组件
1、使用 .vue 文件
<template> <div> <UserCard name="Alice" :age="25" /> <Modal :visible="isModalVisible" @close="toggleModal"> <p>This is the modal content!</p> </Modal> <button @click="toggleModal">Toggle Modal</button> </div> </template> <script setup> import UserCard from './components/UserCard.vue'; import Modal from './components/Modal.vue'; import { ref } from 'vue'; const isModalVisible = ref(false); const toggleModal = () => (isModalVisible.value = !isModalVisible.value); </script>
2、使用 .tsx 文件
import { defineComponent, ref } from 'vue'; import UserCard from './components/UserCard'; import Modal from './components/Modal'; export default defineComponent({ name: 'App', setup() { const isModalVisible = ref(false); const toggleModal = () => (isModalVisible.value = !isModalVisible.value); return () => ( <div> <UserCard name="Alice" age={25} /> <Modal visible={isModalVisible.value} onClose={toggleModal}> <p>This is the modal content!</p> </Modal> <button onClick={toggleModal}>Toggle Modal</button> </div> ); }, });
3、TSX 写法的优缺点
优点:
1、类型支持与代码提示:TSX 能够利用 TypeScript 的类型推断功能,减少开发中的类型错误。
2、灵活性与复用性:TSX 的写法更贴近 JavaScript 和函数式编程的范式,因此能更灵活地编写高阶组件和传递 props。许多复杂逻辑可以通过更纯粹的函数式写法实现。
3、易于集成第三方库:TSX 更符合主流 JavaScript 库(例如 React)的写法。
4、更好的代码组织:对于团队开发中的大型项目,TSX 组件更容易分离逻辑和样式管理,提升代码模块化水平。
缺点:
1、学习成本增加:TSX 更贴近 JavaScript 函数式写法,Vue 开发者需要理解 JSX 语法。
2、可读性降低:TSX 将模板、逻辑和样式混合在一个文件中,尽管提升了灵活性,但可读性不如传统的 .vue 文件结构。
4. 趋势与发展方向
对于复杂的企业级应用,TSX 的灵活性、类型安全性更符合需求。虽然 Vue 社区仍然以 .vue 文件为主流,但对于某些 TS 和 JS 深度开发者来说,TSX 正成为常见选择。Vue 团队未来可能会继续增强对 TSX 的支持,以适应不同的编程习惯。
到此这篇关于Vue 项目中选择 TSX 而非传统 .vue 文件的原因分析的文章就介绍到这了,更多相关vue内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!