Vue3使用TSX

2022 年 4 月 25 日 星期一(已编辑)
/ , ,
478
这篇文章上次修改于 2022 年 4 月 25 日 星期一,可能部分内容已经不适用,如有疑问可询问作者。

Vue3使用TSX

最近尝试在Vue3中使用TSX开发一些小玩具。不出所料,还是遇到许多问题的,尝试写一篇博客来记录一下。

TSX支持

Vue3项目中集成tsx还是很简单的,只需要安装官方维护的vite插件pnpm install @vitejs/plugin-vue-jsx -D,然后在vite配置文件中use一下即可。

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from "@vitejs/plugin-vue-jsx";

export default defineConfig({
  plugins: [
      vue(),
      vueJsx()
  ]
})

然后把目录中以.vue结尾的文件全部换成.tsx,接着以如下格式书写即可

import {defineComponent} from 'vue'

export default defineComponent({
    setup(props, ctx) {
        return () => (
            <>
                <div>Hello World</div>
            </>
        );
    }
})

其实这个插件的核心还是@vue/babel-plugin-jsx,只是封装了一层供vite插件调用,因此tsx的一些基础语法可以直接参看@vue/babel-plugin-jsx来学习,本文就不再叙述了。

Props与TSX

既然我们使用的是tsx,那么vue3.2中的script setup语法糖就无法使用了,因此我们使用vue3.0的方式定义props即可。

import {defineComponent, PropType, Ref, ref} from 'vue'

export default defineComponent({
    setup(props, ctx) {
        const isShow = ref<boolean>(true)
        return () => (
            <>
                <Children isShow={isShow}/>
                <button onClick={()=>isShow.value = !isShow.value}>显示/隐藏</button>
            </>
        );
    }
})

const Children = defineComponent({
    props:{
        isShow:{
            type:Object as PropType<Ref<boolean>>,
            required: true,
        }
    },
    setup(props, ctx) {
        const {isShow} = props
        const inputValue = ref<string>('')
        return () => (
            <>
                <div v-show={isShow.value}>
                    <input type="text" v-model={inputValue.value}/>
                     <p>{inputValue.value}</p>
                </div>
            </>
        );
    }
})
image-20220424220420718

image-20220424220420718

阅读以上代码可以发现在tsx中用ref定义的变量,并不会如用template一样自动解构,还需要手动调用.value。另外v-if、v-for在tsx中是用不了的,但v-show v-model还是可以使用的。

Emit与TSX

我们平日里使用的Vue template中会用 @ 去监听一个事件,但在tsx中我们会用on前缀来替代。

import {defineComponent, PropType, Ref, ref} from 'vue'

export default defineComponent({
    setup(props, ctx) {
         const handleHello = (str:string)=>{
            console.log(str)
         }
        return () => (
            <>
                <Children onHello={handleHello}/>
            </>
        );
    }
})

const Children = defineComponent({
    emits:['hello'],
    setup(props, {emit}) {
        return () => (
            <>
                <button onClick={()=>emit('hello','你好世界')}>emit</button>
            </>
        );
    }
})

这里有个小坑,就是子组件使用emit时,一定要先使用emits:['hello']来声明这个自定义事件,否则父组件会报ts错误。当然你也可以不声明,把父组件改成<Children {...{onHello:handleHello}}/>就可以了。

Slot与TSX

默认插槽

Vue 的 slots 在tsx中也有些改变,我们先来看看默认插槽

import {defineComponent, PropType, Ref, ref} from 'vue'

export default defineComponent({
    setup(props, ctx) {
        return () => (
            <>
                <Children>
                    <p>这是默认插槽</p>
                </Children>
            </>
        );
    }
})

const Children = defineComponent({
    setup(props, {slots}) {
        return () => (
            <>
                {slots.default?.()}
            </>
        );
    }
})

发现我们得调用slots.default?.()来获取插槽内容

具名插槽

import {defineComponent, PropType, Ref, ref} from 'vue'

export default defineComponent({
    setup(props, ctx) {
        return () => (
            <>
                <Children v-slots={{
                    header: () => (
                        <>这是header插槽</>
                    )
                }}>

                </Children>
            </>
        );
    }
})

const Children = defineComponent({
    setup(props, {slots}) {
        return () => (
            <>
                {slots.header?.()}
            </>
        );
    }
})

可以看到,父组件通过 v-slots 属性去定义插槽。当然默认插槽也可以放在v-slots里面定义。default: () => (<>这是默认插槽</>),

作用域插槽

import {defineComponent} from 'vue'

export default defineComponent({
    setup(props, ctx) {
        return () => (
            <>
                <Children v-slots={{
                   content:(scope:{name:string})=> <>{scope.name}</>
                }}>
                </Children>
            </>
        );
    }
})

const Children = defineComponent({
    setup(props, {slots}) {
        return () => (
            <>
                {slots.content?.({name:'suemor'})}
            </>
        );
    }
})

如示例所示,传参即可。

结尾

总而言之Vue3搭配tsx坑还挺多的,比如与一些组件库搭配起来可能会出现各种奇怪的问题,这个以后再说吧,今天就先到这里了。

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...