极致爽文,tsx语法应用vue

程序员他爱做梦 2024-04-24 21:26:52
前言

JSX语法让程序员体验到前所未有的舒爽,而在Vue3中,快速过渡到TSX也是轻而易举的。除了下文介绍的TSX用法外,其他方面与Vue3的使用方式并无二致。TSX所需学习的内容并不繁杂,只是稍微改变了开发习惯,取消了模板语法,让我们能够像编写JavaScript一样书写页面。

工程搭建

通过执行npm init vue来创建一个Vue工程。

工程地址

你可以在以下地址找到本文使用的工程示例:gitee.com/z-shichao/v…

组件定义:defineComponent

在Vue3中,defineComponent是一个用于定义组件的函数API。它的作用主要有三个方面:

创建组件选项对象:defineComponent允许你定义一个包含组件配置信息的选项对象,如组件的属性、方法、生命周期钩子等。类型推断支持:使用defineComponent可以帮助TypeScript更好地推断组件的类型,从而提高开发效率和代码的健壮性。提供组件定义上下文:defineComponent内部对组件选项对象进行一些处理,包括生命周期钩子的转换、模板的编译等,从而提供了一个统一的组件定义上下文,使得组件的定义更加清晰和一致。

这里有个专门讲解defineComponent的文章 :juejin.cn/post/699461…

tsx语法

tsx有种书写模式:函数语法,选项语法

//选项式import { defineComponent } from "vue"export default defineComponent({  setup() {    return () => (<div>vue3+tsx</div>)  }})

//函数式export default defineComponent(() => {  return () => (<div>vue3+tsx</div>)})

使用选项语法还是函数语法主要取决于个人习惯。下文示例将使用选项式进行讲解。

注意:返回的是一个函数,在函数中返回的是一个JSX元素。JSX元素中必须有一个根标签。如果不想使用根标签,可以使用<></>代替,该标签不会在页面中渲染。

插值语法

export default defineComponent({  setup() {    let text = ref<string>('我是文本内容')    return () => (<div>{text.value}</div>)  }})

注意:使用ref定义响应式数据时,在模板中需要使用.value来访问。

事件绑定

export default defineComponent({  setup() {    let text = '我是文本内容'    return () => (<>    <div >{text}</div>    <button onClick={() => { alert('您点击了我')}}>点我</button>    </>)  }})

注意:使用大括号{}进行插值,使用on+事件名(小驼峰命名法)进行事件绑定,自定义事件也是一样的。

jsx中移除了部分指令:v-bin、v-for、v-if

v-bind:使用大括号{}进行包裹

export default defineComponent({  setup() {    let text = '我是文本内容'    let style = {      background: 'red'    }    return () => (<>      <div style={style} >{text}</div>      <button onClick={() => { alert('您点击了我') }}>点我</button>    </>)  }})

v-for:使用数组方法mapexport default defineComponent({  setup() {    let items = ['张三', '李四', '王五']    return () => (<>      {items.map((item) => <div>{item}</div>)}    </>)  }})

v-if:使用三元表达式

export default defineComponent({  setup() {    let isShow = ref<boolean>(true)    return () => (<>      <div>{isShow.value ? <div>我出来饿了</div> : ''}</div>      <button onClick={() => { isShow.value = !isShow.value}}>点我</button>    </>)  }})

注意:js要写在{}里面,返回值是是一个可渲染的元素或元素组成的数组。

插槽默认插槽

import { defineComponent, ref } from "vue"export default defineComponent({  setup(props, { slots }) {    let text = ref<string>('我是默认插槽')    return () => (<Child>{text.value}</Child>)  }})let Child = (props: any, { slots }: any) => {  return <div>{slots.default()}</div>}

具名插槽

import { defineComponent, ref } from "vue"export default defineComponent({  setup(props, { slots }) {    let text = ref<string>('我是默认插槽')    return () => (<Child>      {{        default: () => text.value,        name1: () => '我是插槽1',        name2: () => '我是插槽2'      }}    </Child>)  }})let Child = (props: any, { slots }: any) => {  return <div>    <div>{slots.default()}</div>    <div>{slots.name1()}</div>    <div>{slots.name2()}</div>  </div>}

作用域插槽

export default defineComponent({  setup(props, { slots }) {    let text = ref<string>('我是默认插槽')    return () => (<Child>      {{        default: () => text.value,        name1: () => '我是插槽1',        name2: (parms: string) => <div>          {parms}        </div>      }}    </Child>)  }})let Child = (props: any, { slots }: any) => {  let parms: string = '我是参数'  return <div>    <div>{slots.default()}</div>    <div>{slots.name1()}</div>    <div>{slots.name2(parms)}</div>  </div>}

还可以通过props传参向子组件传递元素

import { defineComponent, ref } from "vue"export default defineComponent({  setup(props, { slots }) {    let text = ref<string>('我是默认插槽')    return () => (<Child      childs={[        <div >我是一</div>,        <div >我是二</div>      ]}></Child>)  }})let Child = (props: any, { slots }: any) => {  return <div>    <div>{props?.childs[0]}</div>    <div>{props?.childs[1]}</div>  </div>}

使用css scoped

在Vue 3 中,如果想要在 TSX 文件中使用 CSS scoped 样式,通常不能直接在 TSX 文件中实现 scoped 样式。你可以在 .vue 单文件组件中的 <script> 标签中编写 TSX 代码,并且将 <script> 标签的 lang 属性设置为 'tsx',然后在 <style> 标签中添加 scoped 属性来实现 scoped 样式。

<script lang="tsx">import { defineComponent } from "vue"export default defineComponent({    setup() {        return () => (<>            <div='text'>css scoped</div>        </>)    }})</script><style scoped>.text{    background: red;}</style>

vue3+tsx中定义props:

import { defineComponent, PropType } from "vue"export default defineComponent({    setup() {        return () => (<>            <div>我是父组件</div>            <Text name={'我 是 传进来的name'} />        </>)    }})//子组件const Text = defineComponent({   props:{      name:{ type:String as PropType<string>, required:true }    },    setup(props) {        return () => (<>            <div>{props.name}</div>        </>)    }})import { defineComponent ,PropType} from "vue"export default defineComponent({    setup() {        return () => (<>            <Text name='我 是 传进来的name' />        </>)    }})

注意:在tsx中定义类型时,只能定义比较笼统的Object、String等,这种类型为什么比较笼统呢,因为在js语言中Object在任何变量的原型上都存在,当你定义一个Object时他就会和any类型时类似的,其他类型同理,当我们想要定义某个类型时,我们只能使用as+ PropType的形式。

简化props的使用:

首先要了解定义string会报错呢,因为我们使用了defineComponent帮我们进行了类型推断定义。那我们可不可以不使用,自己使用ts来规范我们的类型呢。当然可以!!!

方案一:

不适用defineComponent 自己使用ts来进行类型定义,但只支持函数语法和react用法几乎一样

可以看到使用ts也可以进行类型定义,并且更为简便。当然参数在子组件里也是可以定义接收的。缺点就是jsx中是不能使用这种方式的。

import { defineComponent } from "vue"export default defineComponent({    setup() {        return () => (<>            <div>我是父组件</div>            <Text name='张三'/>        </>)    }})interface Props {    name: string,    age?: number}const Text = (props: Props, ctx: any) => {    return <div>{props.name}</div>}

方案二:

混编 这个有篇文章可以看一下 juejin.cn/post/714305…

方案三:

使用# Vue Macros构建项目vue-macros.dev/zh-CN/guide…

优点:类型安全性:使用 TypeScript 结合 TSX 可以提供更好的类型安全性,能够在编译时发现并防止一些常见的错误,如属性类型不匹配、不存在的属性等。更灵活的语法:TSX(或 JSX)语法更加灵活,可以直接在 JavaScript 中编写 HTML 结构,使得组件的编写更加简洁和直观。更好的 IDE 支持:TypeScript 的类型系统使得 IDE 能够提供更好的代码提示、自动补全和错误检查,提高了开发效率。组件复用性:TSX(或 JSX)语法可以让组件更易于复用,因为它们更接近于 JavaScript 语法,可以更方便地通过 JavaScript 函数来生成组件。缺点:学习曲线:对于不熟悉 TypeScript 的开发者来说,学习 TSX(或 JSX)的语法和 TypeScript 的类型系统可能需要一定的时间和精力。构建配置:如果项目中还未使用 TypeScript,引入 TSX 需要进行相应的构建配置,包括安装 TypeScript 相关依赖、修改 webpack 配置等,可能会增加一些额外的工作量。性能影响:相比于模板编译,TSX(或 JSX)语法在运行时需要经过额外的转换和编译,可能会对性能产生一定的影响,尤其是在大型项目中。与模板的差异:TSX(或 JSX)语法与 Vue 的模板语法有一定的差异,可能需要一定的适应时间,并且不支持一些模板特有的语法和指令。总结:

总的来说,TSX(或 JSX)在 Vue 中的使用提供了更好的类型安全性和灵活性,但也需要权衡其引入的学习曲线和对构建配置的影响。在选择是否使用 TSX(或 JSX)时,需要根据项目的实际需求和团队的技术栈来进行权衡和决策。

作者:用户1585826119852链接:https://juejin.cn/post/7352763168902578230

1 阅读:137

程序员他爱做梦

简介:感谢大家的关注