前言
在日常開發中vue
的模版語法在大多數情況都能夠滿足我們的需求,但是在一些複雜的業務場景中使用模版語法就有些麻煩了。這個時候靈活的JSX/TSX
渲染函數就能派上用場了,大多數同學的做法都是將*.vue
文件改爲*.tsx
或者*.jsx
文件。其實我們可以直接在*.vue
文件中直接使用JSX/TSX
渲染函數。
什麼場景需要使用JSX/TSX渲染函數
假設我們現在有這樣的業務場景,在我們的頁面中有個list
數組。我們需要去遍歷這個數組,根據每一項的item去渲染不同的組件。如果tem的數據滿足條件A,那麼就渲染組件A。如果item的數據滿足條件B,那麼就渲染組件B。如果item的數據滿足條件C,那麼就渲染組件C。
如果我們使用vue模版語法去實現這個需求,我們的Page.vue
文件的代碼就需要是這樣的:
<template>
<template v-for="item in list">
<ComponentA v-if="isComponentA(item)" />
<ComponentB v-else-if="isComponentB(item)" />
<ComponentC v-else-if="isComponentC(item)" />
</template>
</template>
<script setup lang="ts">
import ComponentA from "./component-a.vue";
import ComponentB from "./component-b.vue";
import ComponentC from "./component-c.vue";
const list: Array<number> = [1, 5, 3, 2, 1];
const isComponentA = (item): boolean => {
return item % 3 === 0;
};
const isComponentB = (item): boolean => {
return item % 3 === 1;
};
const isComponentC = (item): boolean => {
return item % 3 === 2;
};
</script>
這樣雖然可以實現功能,但是明顯不夠優雅,領導code review時看了直呼搖頭。
在*.jsx/tsx文件中使用JSX/TSX渲染函數
此時機智的小夥伴會說,我們可以使用vue
的setup
方法使用JSX/TSX
渲染函數實現。確實可以,我們來看看具體實現的代碼:
import { defineComponent } from "vue";
import ComponentA from "./component-a.vue";
import ComponentB from "./component-b.vue";
import ComponentC from "./component-c.vue";
export default defineComponent({
setup() {
const list = [1, 5, 3, 2, 1, 0];
function renderDataList(data: Array<number>) {
return data?.map((val) => {
if (val % 3 === 0) {
return <ComponentA />;
} else if (val % 3 === 1) {
return <ComponentB />;
} else {
return <ComponentC />;
}
});
}
return () => {
return <div>{renderDataList(list)}</div>;
};
},
});
首先我們需要將原來的Page.vue
文件改爲Page.tsx
文件,然後我們需要將原來寫在template
中的代碼摞到setup
中。這種寫法有如下幾個痛點:
由於沒有使用vue
的模版語法,所以vue
內置的v-model
等指令和項目中自己封裝的指令等都不能使用了,只能使用js去自己實現。
按照常規的思維,setup
直接返回一個值就行了,但是如果你這樣寫就會收到這樣的報錯:
[Vue warn]: setup() should not return VNodes directly - return a render function instead.
原因是setup()
函數在每個組件中只會被調用一次,而返回的渲染函數將會被調用多次。這樣就導致我們的代碼只能在外面包裹一層匿名函數:
return () => {
return <div>{renderDataList(list)}</div>;
};
在*.vue文件中使用JSX/TSX渲染函數
那麼有沒有方法可以讓我們在使用JSX/TSX
渲染函數的同時,也可以在vue
文件中使用模版語法呢?答案是:當然可以!
首先我們需要導入@vitejs/plugin-vue-jsx
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [vue()],
}
然後我們需要將vue
文件的script
標籤的lang
設置爲tsx或者jsx
。具體的Page.vue
代碼如下:
<template>
<RenderDataList :data="list" />
</template>
<script setup lang="tsx">
import ComponentA from "./component-a.vue";
import ComponentB from "./component-b.vue";
import ComponentC from "./component-c.vue";
const list = [1, 5, 3, 2, 1];
const RenderDataList = (props: { data: Array<number> }) => {
return props.data?.map((val) => {
if (val % 3 === 0) {
return <ComponentA />;
} else if (val % 3 === 1) {
return <ComponentB />;
} else {
return <ComponentC />;
}
});
};
</script>
在上面這個例子中我們定義了一個RenderDataList
,然後在template
中可以直接將RenderDataList
當作一個組件使用。vscode也會給出智能提示。
在react
中,這種場景我們可以將RenderDataList
當作一個函數去使用,然後在模版中直接調用這個函數就行了。但是在vue
中,RenderDataList
只能當做一個組件使用,不能當做函數調用。
還有一點需要避坑的是,假如我們的props中定義了一個駝峯命名法的變量,例如:pageNum
。在template
中傳入pageNum
的時候必須寫成:pageNum="xxx"
,不能寫成:page-num="xxx"
。
總結
這篇文件介紹瞭如何在*.vue
文件中直接使用JSX/TSX
渲染函數,只需要導入@vitejs/plugin-vue-jsx
,然後將script
標籤的lang
設置爲tsx或者jsx
。就可以在script
中直接定義組件,然後在template
中直接使用組件就可以了。這樣我們既可以使用JSX/TSX
渲染函數的靈活性,也可以使用vue
模版語法中內置的指令等功能。
如果我的文章對你有點幫助,歡迎關注公衆號:【歐陽碼農】,文章在公衆號首發。你的支持就是我創作的最大動力,感謝感謝!