写 TSX 的目的
element-plus 图标集有很多,但有时需要动态使用某个图标,把所有可能用到的图标都列举出来,通过 v-if
在组件中决定到底渲染哪一个,很费时。
.vue
单文件组件中做不到的,可以尝试用 TSX 和渲染函数来做。比如,我想做一个底部有文字的图标,其实可以通过插槽把图标插入到组件中:
<div class="header f-c-s">
<TextIcon icon="menu" :icon-size="2" :text-size="1" />
</div>
这个组件我只需要传递一个 props icon 指定图标的名称即可使用所有 element-plus 图表中的其中一个。
配置 TSX
cnpm i @vitejs/plugin-vue-jsx -D
// vite.config.ts
import vue from "@vitejs/plugin-vue";
import { defineConfig } from "vite";
import vueJsx from "@vitejs/plugin-vue-jsx";
export default defineConfig({
plugins: [
vue(),
vueJsx()
]
});
TSX 创建组件
import { defineComponent, resolveComponent, h } from "vue";
function isText(props: any) {
if (props.text) {
return (
<div class="text mt-1" style={{ fontSize: props.textSize + "rem" }}>
{props.text}
</div>
);
}
}
export default defineComponent({
props: {
icon: {
type: String,
required: true
},
text: {
type: String,
default: ""
},
iconSize: {
type: Number,
default: 1
},
textSize: {
type: Number,
default: 1
}
},
setup(props, ctx) {
// resolveComponent 接收字符串,解析对应的 element-plus 图标组件
const elIcon = resolveComponent(props.icon);
// h 函数渲染 elIcon 组件
return () => (
<div class="i-icon text-center">
<div class="f-c-c">
<el-icon style={{ fontSize: props.iconSize + "rem" }}>{h(elIcon)}</el-icon>
</div>
{isText(props)}
</div>
);
}
});
把图标的组件名称,通过 props 传递给 TextIcon 组件,通过 resolveComponent
解析组件,h
函数渲染该组件。
注意事项
在 TSX 中使用 Element-Plus 组件要全部导入,不能按需自动导入,否则 resolveComponent
不能解析组件:
// main.ts
// import vue
import { createApp } from "vue";
import App from "./App.vue";
// import element-plus
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
const app = createApp(App);
// all element icons
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
app.use(ElementPlus);
app.mount("#app");
总结
在 .vue
组件中,模板不能通过一个字符串解析组件,我们可以通过 TSX 来做,利用 resolveComponent
函数接收一个组件的名称(字符串)进行渲染,且该组件是已经全局注册过的。总而言之,TSX 非常灵活,在万不得已的情况下才用,一般 .vue
模板组件已经够用了。