Vue with TSX 的一些爽点
TSX
其实也不是什么很新鲜的东西,Vue
对其的支持也有很长一段时间了,但是!在 Vue
里头写 TSX
实在是太爽了 😱
用 TSX 的一个契机是源自之前封装的表格构造器的单元格渲染,这里一开始我就考虑了,加入了函数 render
来渲染 VNode
,这样就能够自定义每个单元格
在没加入 TSX
之前就需要用 h
函数,这里内容可以是
h
import { ElTooltip } from 'element-plus'
/**
* Renders a user field with avatar, nickname, and phone number.
* @param item An object containing the user's avatar, nickname, phone, and vId.
* @param h The virtual DOM function.
* @returns A virtual DOM node representing the user field.
*/
export const UserField = (
item: { avatar: string; nickname: string; phone: string; vId?: string },
h: any
) => {
return h(
ElTooltip,
{ content: item.vId || '-', placement: 'top', effect: 'dark' },
() =>
h(
'div',
{
class: 'flex items-center gap-[5px]',
},
[
h('img', { src: item.avatar, class: 'w-[45px] h-[45px] rounded-[5px]' }),
h('div', { class: 'flex flex-col gap-[3px]' }, [
h('span', { class: 'text-xs text-gray-700' }, item.nickname),
h('span', { class: 'text-xs text-slate-600' }, item.phone || '-'),
]),
]
)
)
}
不仅读起来比较费劲,写起来更是十分费劲,或者说用模板的方式?
当然也是可以的,不过,模板是一个单独的文件,自定义的单元格越多,.vue
文件就会越多,这种场景下我觉得它并不是最好的选择
TSX
<script lang='tsx' setup>
const DataTableNode = DataTable<TableType>({
items: tableData,
...
columns: [
{
label: '状态',
render: item => <ItemStatus item={item} />,
},
]
...
}
function ItemStatus({ item }: { item: TableType }) {
const status = StatusValues.find(v => item.recordStatus === String(v.value)) || {
label: '未知状态',
bgColor: 'bg-gray-500/10',
textColor: 'text-gray-500',
}
return (
<>
<Tag str={status.label} bgColor={status.bgColor} textColor={status.textColor} />
</>
)
}
</script>
// 在 <template> 中使用
<template>
<div class="p-[20px]">
<DataTableNode />
</div>
</template>
这里的 DataTable
是一个返回 VNode
的函数
/**
* Creates a DataTable component with the given table definition.
* @template T The type of data in the table.
* @param {TableDefine<T>} define The table definition.
* @returns {VNode} The DataTable component.
*/
export default <T>(define?: TableDefine<T>) => {
return h(DataTable, define)
}
About
本质上的优势就是可以在同组件内编写,并且相比直接使用 h
函数要方便很多
另外,对于创建更加复杂的组件,我会选择使用 defineComponent
和 TSX
配合,这样做由于是创建的 Vue
组件,可以使用生命周期函数等等,和传统的 FunctionalComponent
比起来可控性更好,比如:
type Props = {
item?: TheTypeOfItem
refresh: () => void
}
const DialogContent = defineComponent({
props: {
item: {
type: Object as PropType<TheTypeOfItem>,
},
refresh: {
type: Function as PropType<() => void>,
},
close: {
type: Function as PropType<() => void>,
required: true,
},
},
setup(props, ctx) {
const form = ref<ShopMallStoreRecord>(props.item || {})
const DataFormNode = DataForm<ShopMallStoreRecord>({
modelValue: form,
labelWidth: 80,
formItems: [
...
],
actions: [
{
type: 'default',
text: '返回',
handler: () => {
props.close?.()
},
},
{
type: 'primary',
text: '提交',
verify: true,
show: item => !item.id,
handler: () => {
// TODO
},
},
],
})
return {
DataFormNode,
}
},
render() {
return <div class="px-[20px]">{this.DataFormNode}</div>
},
})
const show = (prop?: Props) => {
const instance = Dialog.init({
title: 'Dialog Title',
width: 650,
content: () => (
<DialogContent item={prop?.item} refresh={prop?.refresh} close={instance!.close} />
),
})
}
export default { show }
空空如也!