This is an old revision of the document!
tsx component best practice
bare bone
import { defineComponent, PropType } from 'vue'
const props = {
modelValue: {
type: Object as PropType<__MODEL_TYPE__>,
default: () => ({})
},
'onUpdate:modelValue': {
type: Function as PropType<(val: __MODEL_TYPE__) => void>
}
}
export default defineComponent({
props,
setup(props) {
return () => <></>
}
})
import { defineComponent } from 'vue'
export default defineComponent(
<T,>(props: { message: T }) => {
return () => <></>
},
{
props: []
}
)
import { defineComponent } from 'vue'
export default defineComponent({
setup() {
return () => <></>
}
})
import { defineComponent } from 'vue';
export interface Expose {
}
export default defineComponent({
name: 'App',
props: { modelValue: { type: Object as PropType<FormData>, required: true } },
emits: ['update:modelValue'],
setup(props: { a: 1 }, { emit, slots, expose }) {
const count = ref(0);
const inc = () => {
count.value++;
};
expose({ ... } satisfies Expose) // https://github.com/vuejs/core/issues/6643#issuecomment-2232546917
return () => (
<div onClick={withModifiers(inc, ['self'])}>{count.value}</div>
<h1>{slots.default ? slots.default() : 'foo'}</h1>
);
},
});
// In other components
import CompA, {Exposed} from "./CompA"
const componentRef = ref<ComponentInstance<typeof CompA> & Exposed>()
<CompA ref={el => componentRef.value = el}>
{{
default: () => 'default',
slotA: () => 'slotA'
}}
</CompA>
tsx table
import BaseContainer from '@/components/BaseContainer'
import Pagination from '@/components/Pagination'
import { ElForm, ElFormItem, ElInput, ElTable, ElTableColumn, ElButton } from 'element-plus'
import { defineComponent, onMounted, ref } from 'vue'
import {ItemType} from './types'
type PaginationConfiguration = Pick<IResponsePage, 'total' | 'pageNum' | 'pageSize'>
type QueryParams = Partial<Pick<Item, never>>
type Item = ItemType
export default defineComponent({
setup() {
const loading = ref(false)
const tableData = ref<Item[]>([])
const queryParams = ref<QueryParams>({})
const paginationConfig = ref<PaginationConfiguration>({
total: 0,
pageNum: 1,
pageSize: 10
})
function handleQuerySearch() {
getTableData()
}
function handleQueryReset() {
queryParams.value = {}
getTableData()
}
function handleAdd() {}
// @ts-expect-error
function handleEdit(row: Item) {}
// @ts-expect-error
function handleDelete(row: Item) {}
async function getTableData() {
// @ts-expect-error
const res = { data: [{}] }
loading.value = true
// paginationConfig.value.total =
loading.value = false
}
function handleKeydown(e: KeyboardEvent) {
if (e.key === 'Enter') handleQuerySearch()
}
onMounted(() => {
getTableData()
})
return () => {
return (
<BaseContainer fill back>
<div class="flex h-full flex-col">
<ElForm model={queryParams.value} class="flex items-center gap-3 w-full flex-wrap">
<ElFormItem label="被征收人编号" prop="personId">
<ElInput
v-model={queryParams.value.personId}
placeholder="请输入被征收人编号"
clearable
style="width: 200px"
onKeydown={handleKeydown}
/>
</ElFormItem>
<ElFormItem class="ml-auto">
<ElButton type="primary" icon="ElIconSearch" onClick={handleQuerySearch}>
搜索
</ElButton>
<ElButton icon="ElIconRefresh" onClick={handleQueryReset}>
重置
</ElButton>
</ElFormItem>
</ElForm>
<div class="flex mb-3">
<div>
<ElButton type="primary" icon="ElIconPlus" onClick={handleAdd}>
新增
</ElButton>
</div>
</div>
<ElTable class="flex-[1-1-0]" v-loading={loading.value} data={tableData.value}>
<ElTableColumn width="60" type="selection" align="center" />
<ElTableColumn label="序号" width="60" type="index" align="center">
{(scope) => (
<span>
{(paginationConfig.value.pageNum - 1) * paginationConfig.value.pageSize +
scope.$index +
1}
</span>
)}
</ElTableColumn>
<ElTableColumn label="" align="center">
<template>
<div>123</div>
</template>
</ElTableColumn>
<ElTableColumn label="" align="center" prop="" />
<ElTableColumn label="操作" align="center" width="100">
{(scope) => (
<div class="flex align-center justify-center flex-wrap">
<ElButton
link
type="primary"
onClick={() => handleEdit(scope.row)}
>
编辑
</ElButton>
<ElButton
link
type="danger"
onClick={() => handleDelete(scope.row)}
>
删除
</ElButton>
</div>
)}
</ElTableColumn>
</ElTable>
<div class="relative">
<Pagination
layout="->, total, sizes, prev, pager, next, jumper"
v-model:page={paginationConfig.value.pageNum}
v-model:limit={paginationConfig.value.pageSize}
total={paginationConfig.value.total}
onPagination={() => getTableData()}
/>
</div>
</div>
</BaseContainer>
)
}
}
})
tsx _form
import { computed, defineComponent, PropType } from 'vue'
import BaseCard from '@/components/BaseCard/Index'
import type { AssessmentObjective } from './types'
import { ElForm, ElFormItem } from 'element-plus'
const rules = {}
export default defineComponent({
props: {
modelValue: {
type: Object as PropType<AssessmentObjective>,
default: () => ({})
}
},
emits: ['update:modelValue'],
setup(props, { emit }) {
const modelValue = computed({
get() {
return props.modelValue
},
set(val) {
emit('update:modelValue', val)
}
})
return () => (
<ElForm model={modelValue.value} rules={rules} class="flex flex-col gap-3">
<BaseCard title="基础信息">
<div class="grid grid-cols-2 gap-4">
<ElFormItem label="企业名称" prop="companyName">
<span>name</span>
</ElFormItem>
</div>
</BaseCard>
</ElForm>
)
}
})
tsx add
import { defineComponent, ref } from 'vue'
import BaseContainer from '@/components/BaseContainer/BaseContainer.vue'
import Form from './_Form'
import { AssessmentObjective } from './types'
import { ElButton } from 'element-plus'
export default defineComponent({
setup() {
const form = ref<AssessmentObjective>({})
function handleSubmit() {}
return () => (
<BaseContainer fill back>
{{
default: () => <Form v-model={form.value} />,
'header-options': () => (
<ElButton type="primary" onClick={handleSubmit} icon="ElIconDocument">
提交
</ElButton>
)
}}
</BaseContainer>
)
}
})