项目搭建
创建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使用说明
注意事项
-
.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> -
如果不需要用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> </> ); } }); -
引入.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} />