Vue —— 使用vue3+ts+jsx搭建项目

507 阅读2分钟

项目搭建

创建vue项目

使用vue-cli直接创建就可以了,创建的时候选择自定义模板Manually select features

接着勾选以下的几个选择安装依赖:

​ Choose Vue version(vue的版本)、Babel、TypeScript、Router、Vuex、CSS Pre-processors(css预处理)。

安装jsx插件

安装好一些基本依赖后就可以装官方提供的jsx的插件@vue/babel-plugin-jsx

安装:

npm install @vue/babel-plugin-jsx -D

配置Babel:

项目创建好后会有一个babel.config.js,加入此项配置

{
  "plugins": ["@vue/babel-plugin-jsx"]
}

jsx使用说明

注意事项

  1. .vue的文件中直接使用jsx的语法是不会报错的,但ts和jsx同时使用的时候script标签中需要加上lang="tsx"

    <template>
        <div class="experiment">
            <test-a name="11"></test-a>
        </div>
    </template>
    
    <script lang="tsx">
    import { defineComponent } from 'vue';
    
    type prop = {
        name: string;
    };
    const TestA = (props: prop) => <div>{props.name} fdsafdsa</div>;
    
    export default defineComponent({
        components: { TestA },
        setup(props, ctx) {
            return {};
        }
    });
    </script>
    
  2. 如果不需要用template的方式开发,可创建一个.jsx或.tsx的文件进行开发

    import { defineComponent, ref } from 'vue';
    
    export default defineComponent({
        setup(props, ctx) {
            const about = ref('hello about');
            const count = ref(0);
    
            const addCount = () => {
                count.value++;
            };
    
            return () => (
                <>
                    <div class="experiment">{about.value}</div>
                    <button onClick={addCount}>{count.value}</button>
                </>
            );
        }
    });
    
  3. 引入.tsx或者.jsx文件的时候,路径中文件的后缀不需要写。路径中如果写了.tsx会报找不到模块的错误

    import App from './App'
    

关于class和style样式

在react如果要写class样式,class需要改成className才能生效。但在vue里面直接使用class就行了。

正常的情况下jsx中使用class/style和在template中是基本一致的

<div style="display:flex;" class="box"></div>

动态的写法就和template有点不一样

{/* object */}
<div class={{ 'test-red': true }} style={true ? { display: 'flex' } : {}}>hello</div>

{/* object */}
<div class={[true ? 'test-red' : '']} style={[true ? 'display:flex' : '']}>
    class/style
</div>

在jsx里面使用ref,reactive等

defineComponent方式的组件:

import { defineComponent, ref } from 'vue';

export default defineComponent({
    setup(props, ctx) {
        const about = ref('hello about');
        const count = ref(0);
        type TPerson = {
            name:string,
            age:number
        }
        const person = reactive<TPerson>({
            name:'Ivan',
            age:18
        })
        const addCount = () => {
            count.value++;
        };

        return () => (
            <>
                <div class="experiment">{about.value}</div>
                <button onClick={addCount}>{count.value}</button>
                <hr />
                姓名:{person.name},年龄:{person.age}
            </>
        );
    }
});

函数的方式:

import { ref, SetupContext } from 'vue';
const hello = ref<string>('hello home');
const count = ref<number>(0);
const addCount = () => {
    count.value++;
};
const Home = (props, ctx: SetupContext) => {
    return (
        <>
            <div>{hello.value}</div>
            <button onClick={addCount}>{count.value}</button>
        </>
    );
};
export default Home;

注意:如果使用函数来创建组件,那么ref、reative则不能放在组件内部,否则会重新赋值,导致不会响应式变化

使用插槽和具名插槽

const Text = (props, ctx: SetupContext) => {
    return (
        <>
            <div>{ctx.slots.default && ctx.slots.default()}</div>
            <div>{ctx.slots.name && ctx.slots.name()}</div>
        </>
    );
};

const App = (props, ctx) => {

	return (
        <>
        	<Text>
                默认插槽 
                <slot name="name">具名插槽1</slot>
                <span v-slots="name">具名插槽2</span>
            </Text>
        </>
    )
}
export default App;

作用域插槽使用

传参:

const Text = (props, ctx: SetupContext) => {
    return (
        <>
            <div>{ctx.slots.default && ctx.slots.default('传参')}</div>
        </>
    );
};

使用:

const App = (props, ctx) => {

	return (
        <>
        	<Text
                v-slots={{
                    default: (n: string) => <span>{n}</span>
                }}
            />
        </>
    )
}
export default App;

v-if 和 v-for

方式1:

const ifFor = () => {
    const ces = true;
    const ifElse = () => {
        if (ces) return <div>if部分</div>;
        else return <div>else部分</div>;
    };

    const forArr = () => {
        let i = 0;
        return new Array(10).fill('').map(() => {
            i++;
            return <span>{i}</span>;
        });
    };

    return (
        <div>
            {ifElse()}
            {forArr()}
        </div>
    );
};

方式2:

const ifFor = () => {
    return (
        <div>
            { true ? <div>if部分</div> : <div>else部分</div> }
            {
                new Array(10).fill('').map((item,index) => {
                    return <span>map{index} </span>;
                })
            }
        </div>
    );
};

v-model的使用

import { ref, SetupContext } from 'vue';
const count = ref<number>(0);

const Home = (props, ctx: SetupContext) => {
    return (
        <>	
        	{count.value}
           <input type="text" v-model={count.value} />
        </>
    );
};
export default Home;

修饰符

指令的修饰符从原来的.trmi改为_trim

<input type="text" v-model_trim={count.value} />