Vue3提供TSX支持
Vue中常用Template写模板,但也可以使用tsx。
Vue2就已经支持jsx写法,但友好度不高。因为Vue3对TypeScript的支持度高,所以tsx写法越来越被接受。
使用前需要安装@vitejs/plugin-vue-jsx
插件。
安装完后在vite.config.ts引入:
1 2 3 4 5 6 7 8 9
| import vueJsx from '@vitejs/plugin-vue-jsx'
export default defineConfig({ plugins: [ vueJsx(), ], })
|
使用TSX
创建一个App.tsx文件并使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import { defineComponent } from "vue"
export default defineComponent({ setup() { const name = "野兽先辈" return ()=> (<div>{name}</div>) } })
|
直接引入,可以类似组件一样使用
1 2 3 4 5 6 7 8 9
| <template> <div> <ABC></ABC> </div> </template>
<script setup lang="ts"> import ABC from "./App" </script>
|
TSX和Vue语法
ref响应式和v-show
1 2 3 4 5 6 7 8 9 10
| export default defineComponent({ setup() { const name = "野兽先辈" const flag = ref(false)
return ()=> (<div v-show={flag.value}>{name}</div>) } })
|
v-if
1 2 3 4 5 6 7 8 9 10 11 12 13
| export default defineComponent({ setup() { const name = "野兽先辈" const flag = ref(false)
return ()=> (<> <div>{flag.value? <div>true</div>: ""}</div> </>) } })
|
v-for和v-bind
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| export default defineComponent({ setup() { const data = [ { name: "KNN" }, { name: "SNNN" }, { name: "YJSP" }, { name: "RU" }, { name: "BNKRG" }, { name: "SIK" }, ] return ()=> (<> {data.map(v=> { return<div name={v.name}>{v.name}</div> })} </>) } })
|
props和emits
App.tsx:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| interface Props { name?: string }
export default defineComponent({ props: { name:String }, emits: ["on-click"], setup(props:Props,{emit}) { const data = [ { name: "KNN" }, { name: "SNNN" }, { name: "YJSP" }, { name: "RU" }, { name: "BNKRG" }, { name: "SIK" }, ] const click = (item:any)=> { console.log("click",item) emit("on-click",item) } return ()=> (<> <div>props:{props?.name}</div> <hr /> {data.map(v=> { // 函数柯里化 return<div onClick={()=>click(v)}>{v.name}</div> })} </>) } })
|
App.vue:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <template> <div> <ABC name="yajue" @on-click="click2"></ABC> </div> </template>
<script setup lang="ts"> import ABC from "./App"
const click2 = (item:any)=> { console.log("click2",item) } </script>
|
插槽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const A = (_:any,{slots}:any)=> (<> <div>{slots.default? slots.default(): "默认值"}</div> <div>{slots.foo?.()}</div> </>)
export default defineComponent({ setup() { const slot = { default: ()=> (<div>default slots</div>), foo: ()=> (<div>foo slots</div>) } return ()=> (<> <A v-slots={slot}></A> </>) } })
|
v-model
1 2 3 4 5 6 7 8 9 10
| export default defineComponent({ setup() { const v = ref<string>("") return ()=> (<> <input v-model={v.value} type="text" /> <div>{v.value}</div> </>) } })
|
Vite插件制作
用到的库:
1 2 3 4 5
| npm install @vue/babel-plugin-jsx npm install @babel/core npm install @babel/plugin-transform-typescript npm install @babel/plugin-syntax-import-meta npm install @types/babel__core
|
Babel常用于语法转换,比如把ES6语法转换为ES5,提高低版本浏览器的兼容性。
![编译原理](/img/loading.gif)
在项目根目录新建plugin/index.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
import type { Plugin } from "vite"
import * as babel from "@babel/core"
import jsx from "@vue/babel-plugin-jsx"
export default function(): Plugin { return { name: "vite-plugin-vue-tsx", async transform(code, id) { if(/.tsx$/.test(id)) { const ts = await import("@babel/plugin-transform-typescript").then(r=>r.default) const res = await babel.transformAsync(code,{ ast:true, configFile:false, babelrc:false, plugins:[jsx,[ts,{isTSX:true,allowExtensions:true}]] }) return res?.code } return code } } }
|
同时在tsconfig的include中加入该路径,就可以作为插件使用了。