前言
在日常开发中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