以 JSX 的方式来编写 Vue3 代码

创建项目

  1. 使用 vue ui 创建 vue3 项目

  2. 安装 vue-router vuex @vue/cli-plugin-typescript, @vue/babel-plugin-jsx

  3. 修改 babel.config.js 文件

module.exports = {
    presets: [
        '@vue/cli-plugin-babel/preset'
    ],
    plugins: ["@vue/babel-plugin-jsx"]
}
  1. 修改全部 .vue -> .jsx, 模板如下
import {defineComponent} from 'vue';

export default defineComponent({
    name: "",
    setup() {
        return () => (
            <>

            </>
        )
    }
})

路由

RouterView

<router-view/> 是一样的用法

import {defineComponent} from 'vue';
import {RouterView} from 'vue-router'

export default defineComponent({
    setup() {
        return () => <RouterView/>
    }
})
import {defineComponent} from 'vue';
import {RouterLink} from 'vue-router'

export default defineComponent({
    name: "RouterLinkDemo",
    setup() {
        return () => <RouterLink to={'/home'}/>
    }
})

Fragment

一个组件返回多个元素,和 React.Fragment 差不多
短语法 <></>

import {defineComponent, Fragment} from 'vue';

export default defineComponent({
    name: "FragmentDemo",
    setup() {
        const a = (
            <>
                <div>A</div>
                <div>A</div>
            </>
        )
        return () => (
            <Fragment>
                {a}
                <div>b</div>
            </Fragment>
        )
    }
})

插槽

带有插槽的组件

创建 ASlotDemo 组件,ASlotDemo 有具名插槽 header,范围插槽 footer

在模板中定义插槽需要用到 <slot/>, jsx 中使用renderSlot函数渲染插槽

renderSlot 接收 Slots, 插槽名,插槽数据,进行渲染

import {defineComponent, renderSlot} from "vue";

export default defineComponent({
    name: "ASlotDemo",
    setup(props, {slots}) {
        const {default: defaultSlot, header, footer} = slots;
        const footerData = {
            text: "2020-1-20"
        }
        return () => (
            <>
                <div>
                    {
                        header !== undefined ? renderSlot(slots, 'header') : "默认 header"
                    }
                </div>
                <div>
                    {
                        defaultSlot !== undefined ? renderSlot(slots, 'default') : "没有传递默认插槽"
                    }
                </div>
                <div>
                    {
                        footer !== undefined ? renderSlot(slots, 'footer', footerData) : "默认 footer" + footerData.text
                    }
                </div>
            </>
        )
    }
})

使用

在使用范围插槽时,可以定义个接口,获得语法提示

import {defineComponent} from "vue";
import ASlotDemo from "@/components/slot/ASlotDemo";

interface IFooterSlotData {
    text: string;
}

export default defineComponent({
    name: "BSlotDemo",
    setup() {
        return () => (
            <>
                <ASlotDemo>
                    我是: BSlotDemo
                </ASlotDemo>
                <ASlotDemo>
                </ASlotDemo>

                <ASlotDemo v-slots={{
                    default: () => <div>slots使用方式1</div>,
                    header: () => <span>header1</span>,
                }}/>
                
                <ASlotDemo>
                    {{
                        default: () => <div>slots使用方式2</div>,
                        header: () => <span>header2</span>,
                    }}
                </ASlotDemo>

                <ASlotDemo v-slots={{
                    default: () => <div>范围插槽使用</div>,
                    header: () => <span>范围插槽header</span>,
                    footer: (value: IFooterSlotData) => <span>获取范围插槽的值: {value.text}</span>,
                }}/>
            </>
        )
    }
})

emits

在父组件使用时,必须 on + 事件名(事件名第一个字母必须大写)

// AEmitsDemo.jsx
import {defineComponent} from 'vue';

export default defineComponent({
    name: "AEmitsDemo",
    emits: ['click', 'getDate'],
    setup(props, {emit}) {
        const click = () => {
            console.log('点击++++++++')
            emit("click")
        }
        return () => (
            <>
                <div onClick={click}>点击</div>
                <div onClick={() => emit("getDate", 10)}>获取数据</div>
            </>
        )
    }
})

// BEmitsDemo.jsx
import {defineComponent} from 'vue';
import AEmitsDemo from "@/components/emits/AEmitsDemo";

export default defineComponent({
    name: "BEmitsDemo",
    setup() {
        const click = () => {
            console.log('点击---------')
        }
        const getData = (value: number) => {
            console.log(value);
        }
        return () => <AEmitsDemo onClick={click} onGetData={getData}/>
    }
})

源码: https://github.com/NikolasSky/vue3-tsx

posted @ 2021-01-29 14:35  无聊的人_nikolas  阅读(1482)  评论(0编辑  收藏  举报