1.布局 <el-row> <el-col :span="21"> <div class="mb8" style="width: 100%"> 按钮区 </div> </el-col> </el-row>
2,图标
<el-button icon="图标名" > </el-button>
<el-row>
<el-col :span="24">
<div class="mb8">
<el-button icon="search" type="primary" @click="getDataList" v-auth="'base_unitType_view'">
{
{ $t('translate.queryBtn') }}
</el-button>
<el-button icon="Refresh" @click="resetQuery" v-auth="'base_unitType_view'">{
{
$t('translate.resetBtn')
}}
</el-button>
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
v-auth="'base_unitType_add'"
>
{
{ $t('translate.addBtn') }}
</el-button>
<el-button icon="edit" type="primary" :disabled="single|| selectDelFlag[0].delFlag==1"
v-auth="'base_unitType_edit'" class="ml10"
@click="formDialogRef.openDialog(selectObjs[0])"> {
{ $t('translate.editBtn') }}
</el-button>
<el-button plain :disabled="multiple" icon="Remove" type="" v-auth="'base_unitType_del'"
@click="handleDelete(selectObjs)">
{
{ $t('translate.delBtn') }}
</el-button>
<el-button :disabled="multiple || ExecuteEffectCheck" type="primary" class="ml10" v-auth="'base_unitType_edit'"
@click="executeEffect(selectObjs)" icon="CircleCheck">
{
{ $t('translate.effective') }}
</el-button>
<el-button :disabled="multiple || LoseEfficacyCheck" icon="Warning" type="primary" v-auth="'base_unitType_edit'"
class="ml10"
@click="executeLapse(selectObjs)">
{
{ $t('translate.inVain') }}
</el-button>
</div>
</el-col>
</el-row>
1.控制新建修改按钮是否禁用逻辑
2.生效失效按钮控制逻辑
3.生效失效按钮执行逻辑
4.tabs标签
5.列表展示
5.1代码阅读
在创建一个符合该接口结构的响应式状态对象
state
。以下是它们之间的具体关系:1. 接口定义
BasicTableProps
接口定义了表格组件所需的各种属性,包括查询表单、数据列表、分页信息等。它为组件的状态提供了一个结构化的类型约束。2. 响应式状态对象
const state: BasicTableProps = reactive<BasicTableProps>({ queryForm: {}, pageList: fetchList });
- 类型约束:在这段代码中,
state
被声明为BasicTableProps
类型,这意味着state
对象必须符合BasicTableProps
接口中定义的结构。- 响应式对象:使用
reactive
函数将一个普通对象转换为响应式对象,使得对state
的任何修改都会自动反映到 UI 上。3. 属性赋值
queryForm: {}
:这是BasicTableProps
接口中的一个属性,初始化为一个空对象,通常用于存储查询条件。pageList: fetchList
:这是BasicTableProps
接口中的一个方法属性,指向一个名为fetchList
的函数,该函数用于获取数据列表。4. 关系总结
- 结构一致性:
state
的定义遵循了BasicTableProps
接口的结构,确保了类型安全。- 状态管理:通过
state
,您可以在组件中管理与表格相关的所有状态,这些状态通过接口得到了清晰的定义。
表格样式:
1. 定义表格配置接口
在一个
.ts
文件中定义表格的相关配置,包括样式和其他属性。可以使用 TypeScript 的接口来确保类型安全。2. 在组件中使用表格配置
在需要使用表格的 Vue 组件中,导入这个配置,并进行解构使用。
表格高度:
import { ref, onMounted, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue'; const FIXED_HEIGHT = 230; // 固定高度 export default function () { const tableHeight = ref(0); const { proxy } = getCurrentInstance(); const calculateTableHeight = (includeButtonRef = false) => { nextTick(() => { const queryHeight = proxy.$refs.queryRef ? proxy.$refs.queryRef.$el.offsetHeight : 0; const tabsHeight = proxy.$refs.tabsRef ? proxy.$refs.tabsRef.$el.offsetHeight : 0; const buttonHeight = includeButtonRef && proxy.$refs.buttonRef ? proxy.$refs.buttonRef.$el.offsetHeight : 0; tableHeight.value = window.innerHeight - queryHeight - tabsHeight - buttonHeight - FIXED_HEIGHT; }); }; const handleResize = () => { calculateTableHeight(); // 计算不包含按钮的高度 }; onBeforeMount(() => { window.addEventListener('resize', handleResize); }); onBeforeUnmount(() => { window.removeEventListener('resize', handleResize); }); onMounted(() => { calculateTableHeight(); // 初始计算 }); return { tableHeight, calculateTableHeight, }; }
代码分析
引入依赖:
import { ref, onMounted, onBeforeUnmount, nextTick, getCurrentInstance } from 'vue';
这里引入了 Vue 的一些组合式 API 函数,用于管理响应式状态和生命周期钩子。
定义响应式变量:
const tableHeight = ref(0);
使用
ref
创建一个响应式变量tableHeight
,用于存储计算后的表格高度。获取当前实例:
const { proxy } = getCurrentInstance();
通过
getCurrentInstance
获取当前组件实例的proxy
,以便访问组件的引用。生命周期钩子:
onBeforeMount
:在组件挂载之前添加窗口的resize
事件监听器。onBeforeUnmount
:在组件卸载之前移除事件监听器。onMounted
:组件挂载后,计算表格高度。计算表格高度的函数:
const $_calTableHeight = (() => { nextTick(() => { tableHeight.value = window.innerHeight - (proxy.$refs.queryRef ? proxy.$refs.queryRef.$el.offsetHeight : 0) - (proxy.$refs.tabsRef ? proxy.$refs.tabsRef.$el.offsetHeight : 0) - 230; }); });
这个函数在 DOM 更新后计算表格的高度。它考虑了其他元素的高度(如
queryRef
和tabsRef
),并从窗口高度中减去这些高度和一个固定值(230)。使用:
行点击:
export function clickRow( table: any, selectDataList: any[], row: any, e: Event, data: any[], type?: number, open?: boolean ) { const { ctrlKey, metaKey } = e as KeyboardEvent; // 进行类型断言 let selectedRow: any = null; // 处理已选中行的逻辑 if (selectDataList.length > 0 && type) { selectedRow = selectDataList[0]; if (selectedRow === row) { table.toggleRowSelection(row, false); return; } // 取消之前选中的行 table.toggleRowSelection(selectedRow, false); // 选中当前点击的行 table.toggleRowSelection(row, true); } // 不可选规则 if (row.roleId === '1' || (row.username === 'admin') || (row.verificationState === '1' && open)) { return; } const rowIndex = findRowIndex(data, row); const selected = isRowSelected(selectDataList, row); if (ctrlKey || metaKey) { handleMultiSelect(table, data, rowIndex, selectDataList); } else { // 单选逻辑 table.toggleRowSelection(row, !selected); } } // 辅助函数:查找行索引 function findRowIndex(data: any[], row: any) { return data.findIndex(item => { return item.id === row.id || item.userId === row.userId || item.roleId === row.roleId || item.publicId === row.publicId || item.busCode === row.busCode; }); } // 辅助函数:检查行是否已选中 function isRowSelected(selectDataList: any[], row: any) { return selectDataList.some(item => { return item.id === row.id || item.userId === row.userId || item.roleId === row.roleId || item.publicId === row.publicId || item.busCode === row.busCode; }); } // 辅助函数:处理多选逻辑 function handleMultiSelect(table: any, data: any[], rowIndex: number, selectDataList: any[]) { const lastCheckIndex = findRowIndex(data, selectDataList[selectDataList.length - 1]); const minIndex = Math.min(rowIndex, lastCheckIndex); const maxIndex = Math.max(rowIndex, lastCheckIndex) + 1; // 在范围内选中行 data.slice(minIndex, maxIndex).forEach(item => table.toggleRowSelection(item, true)); }
clickRow
函数是一个复杂的行点击事件处理器,主要用于管理表格行的选择状态。下面是对该函数的详细分析及一些优化建议。代码分析
参数说明:
table
: 表格的引用,通常是一个组件实例。selectDataList
: 当前已选中的行数据列表。row
: 被点击的行数据。e
: 原生事件对象,用于检查按键状态。data
: 表格的所有数据列表。type
: 可选参数,可能用于指示某种选择模式。open
: 可选参数,可能用于控制某些逻辑。行选择逻辑:
- 函数首先检查是否有已选中的行,如果有且
type
存在,则根据当前点击的行决定是否取消选中或选中该行。- 通过
table.toggleRowSelection
方法来选中或取消选中行。不可选规则:
- 角色 ID 为
1
的行和用户名为admin
的行无法被选中。- 如果
verificationState
为1
并且open
为true
,则该行也不可选。多选逻辑:
- 如果按下
Ctrl
或Meta
键,支持多选功能。- 计算并选择范围内的行。
状态更新:
- 根据当前行是否已经选中,决定是否将其选中或取消选中。
- 使用
排序:
展示生效失效;
5.2 知识点了解:
1) 表格组件-hook
2)代码阅读:
useTable
函数-- 通用的表格组件配置和分页逻辑处理的自定义 Hook(在 Vue 3 中称为 Composable)。tables.ts----高度可复用的表格组件,它支持分页、排序、查询等多种功能。useTable
提供了一个集中的地方来管理这些逻辑,使得你的组件代码更加简洁和易于维护。
使用:
useTable
是一个 Vue Composition API 的自定义 Hook(Composable),用于处理表格组件的各种状态管理和数据请求逻辑。下面是对useTable
函数的详细解释和总结:1. 默认配置
typescript
深色版本
1const defaultOptions: BasicTableProps = { 2 dataListLoading: false, 3 createdIsNeed: true, 4 isPage: true, 5 queryForm: {}, 6 dataList: [], 7 pagination: { 8 current: 1, 9 size: 20, 10 total: 0, 11 pageSizes: [1, 10, 20, 50, 100, 200, 500, 1000], 12 layout: 'total, sizes, prev, pager, next, jumper', 13 }, 14 dataListSelections: [], 15 loading: false, 16 selectObjs: [], 17 descs: [], 18 ascs: [], 19 props: { 20 item: 'records', 21 totalCount: 'total', 22 }, 23};
dataListLoading
:表示数据是否正在加载中。
createdIsNeed
:是否在创建时自动请求数据。
isPage
:是否显示分页组件。
queryForm
:查询条件表单对象。
dataList
:表格展示的数据数组。
pagination
:分页属性,包括当前页码、每页条数、总条数等。
dataListSelections
:当前选中的数据项。
loading
:表示是否正在从服务器加载数据。
selectObjs
:表格数据项的选择数据。
descs
和ascs
:排序字段和方向。
props
:自定义数据属性,如item
表示数据记录,totalCount
表示总条数。2. 合并默认配置和传入配置
typescript
深色版本
1const mergeDefaultOptions = (options2: any, props: any): BasicTableProps => { 2 for (const key in options2) { 3 if (!Object.getOwnPropertyDescriptor(props, key)) { 4 props[key] = options2[key]; 5 } 6 } 7 return props; 8}; 9 10const state = mergeDefaultOptions(defaultOptions, options);
mergeDefaultOptions
:将默认配置和传入的配置合并,确保所有必要的属性都被设置。
state
:最终的状态对象,包含了合并后的配置。3. 数据请求
typescript
深色版本
1const query = async () => { 2 if (state.pageList) { 3 try { 4 state.loading = true; 5 let res: any; 6 if (state.ids) { 7 res = await state.pageList({ 8 ...state.queryForm, 9 current: state.pagination?.current, 10 size: state.pagination?.size, 11 descs: state.descs?.join(','), 12 ascs: state.ascs?.join(','), 13 }, state.ids); 14 } else { 15 res = await state.pageList({ 16 ...state.queryForm, 17 current: state.pagination?.current, 18 size: state.pagination?.size, 19 descs: state.descs?.join(','), 20 ascs: state.ascs?.join(','), 21 }); 22 } 23 state.dataList = state.isPage ? res.data[state.props.item] : res.data; 24 state.pagination!.total = state.isPage ? res.data[state.props.totalCount] : 0; 25 } catch (err: any) { 26 ElMessage.error(err.msg || err.data.msg); 27 } finally { 28 state.loading = false; 29 } 30 } 31};
query
:异步函数,用于发起数据请求。
state.loading
:在请求开始前设置为true
,请求结束后设置为false
。
state.pageList
:调用传入的数据请求函数,传递查询参数。
state.dataList
和state.pagination.total
:根据返回的数据更新表格数据和总条数。4. 生命周期钩子
typescript
深色版本
1onMounted(() => { 2 if (state.createdIsNeed) { 3 query(); 4 } 5});
onMounted
:在组件挂载时,如果createdIsNeed
为true
,则自动发起数据请求。5. 事件处理函数
typescript
深色版本
1const sizeChangeHandle = (val: number) => { 2 state.pagination!.size = val; 3 query(); 4}; 5 6const currentChangeHandle = (val: number) => { 7 state.pagination!.current = val; 8 query(); 9}; 10 11const sortChangeHandle = (column: any) => { 12 const prop = other.toUnderline(column.prop); 13 if (column.order === 'descending') { 14 state.descs?.push(prop); 15 if (state.ascs!.indexOf(prop) >= 0) { 16 state.ascs?.splice(state.ascs.indexOf(prop), 1); 17 } 18 } else if (column.order === 'ascending') { 19 state.ascs?.push(prop); 20 if (state.descs!.indexOf(prop) >= 0) { 21 state.descs?.splice(state.descs.indexOf(prop), 1); 22 } 23 } else { 24 if (state.ascs!.indexOf(prop) >= 0) { 25 state.ascs?.splice(state.ascs.indexOf(prop), 1); 26 } 27 if (state.descs!.indexOf(prop) >= 0) { 28 state.descs?.splice(state.descs.indexOf(prop), 1); 29 } 30 } 31 query(); 32};
sizeChangeHandle
:处理分页大小改变事件,更新state.pagination.size
并重新请求数据。
currentChangeHandle
:处理当前页码改变事件,更新state.pagination.current
并重新请求数据。
sortChangeHandle
:处理排序事件,更新排序字段和方向,并重新请求数据。6. 获取数据列表
typescript
深色版本
1const getDataList = (refresh?: any) => { 2 if (refresh !== false) { 3 state.pagination!.current = 1; 4 } 5 // 处理时间范围 6 // ... 7 query(); 8};
getDataList
:获取数据列表,可选择是否刷新当前页码。处理各种时间范围的查询条件,并重新请求数据。7. 下载文件
typescript
深色版本
1const downBlobFile = (url: string, requestBody: any, fileName: string, method?: string) => { 2 return other.downBlobFile(url, requestBody, fileName, method); 3};
downBlobFile
:下载文件的辅助函数,调用other.downBlobFile
进行实际的文件下载。8. 表格样式
typescript
深色版本
1const tableStyle: TableStyle = { 2 cellStyle: { height: '40px' }, 3 headerCellStyle: { 4 height: '40px', 5 background: 'var(--el-table-row-hover-bg-color)', 6 color: 'var(--el-text-color-primary)', 7 }, 8};
tableStyle
:定义表格的通用样式。返回值
1return { 2 tableStyle, 3 getDataList, 4 sizeChangeHandle, 5 currentChangeHandle, 6 sortChangeHandle, 7 downBlobFile, 8};
tableStyle
:表格样式。
getDataList
:获取数据列表的函数。
sizeChangeHandle
和currentChangeHandle
:分页大小和页码改变的处理函数。
sortChangeHandle
:排序事件的处理函数。
downBlobFile
:下载文件的辅助函数。总结
useTable
Composable 提供了一个完整的解决方案来管理表格组件的状态和数据请求逻辑。它处理了以下主要功能:
初始化和合并配置:确保所有必要的属性都被正确设置。
数据请求:自动或手动发起数据请求,并处理响应数据。
生命周期管理:在组件挂载时自动请求数据。
事件处理:处理分页、排序等事件,并重新请求数据。
辅助功能:提供下载文件和定义表格样式的辅助函数。
通过这种方式,你可以轻松地在 Vue 组件中使用这个 Composable 来管理复杂的表格逻辑。
state
对象集成BasicTableProps
的所有属性ÿ