去掉element表格排序的null状态

本文介绍了一种优化Element UI表格排序的方法,通过自定义排序触发函数,实现仅保留升序和降序状态,避免null状态出现,提升用户体验。文章详细解释了如何通过保存上次排序状态并取相反值来实现这一目标。

element表格排序有三种状态,升序、降序、null,现在想要实现的效果为只要升序和降序。
主要思想是检测返回的排序值是否为null,如果是的话则和上一个排序取相反的值(需要先用变量保存上一次的排序值),代码如下:

//这是排序触发函数
change_sort(row) {
    if (row.order === null) {
        this.save_sort === 'descending' ? row.order = 'ascending' : row.order = 'descending'
        row.column.order = row.order
    }
    if (row.order == 'ascending') { //降序
        this.listParams.sort = 1;
    } else {
        this.listParams.sort = 0;
    }
    this.save_sort = row.order;
    this.getList();
},
// 动态表格生成器 class DynamicTableGenerator { /** * 构造函数 * @param {Object} config - 表格配置对象 */ constructor(config) { this.config = { searchFields: [], // 设置默认值,避免undefined错误 ...config }; } /** * 生成表格组件的JavaScript代码 * @returns {string} - 完整的表格组件JS代码 */ generateTableComponent() { const { componentId, tableName, columns = [], // 增加默认值 hasSearch = false, // 增加默认值 searchFields, accountId = '', // 增加默认值 year = new Date().getFullYear() // 增加默认值 } = this.config; // 1. 生成查询字段的data部分(统一缩进,避免生成代码杂乱) let queryData = ''; if (hasSearch && searchFields.length > 0) { queryData = `query: { ${searchFields.map(field => ` ${field.field}: ''`).join(',\n')} },`; } // 2. 生成列配置(修复JSON转义,确保对象格式正确) const columnsConfig = JSON.stringify(columns, null, 6) // 缩进6格,匹配组件内data结构 .replace(/"([^"]+)":/g, '$1:') // 去掉key的双引号,转为Vue可识别的对象字面量 .replace(/\\"/g, '"'); // 处理转义引号(如label含双引号时) // 3. 生成搜索框模板(统一缩进,避免污染外层template) let searchTemplate = ''; if (hasSearch && searchFields.length > 0) { const colSpan = Math.max(2, Math.floor(24 / searchFields.length)); // 最小占2列,避免布局错乱 // 用String.raw确保内部引号不被转义,同时统一缩进为4格(匹配template内部结构) searchTemplate = String.raw` <!-- 查询条件区域 --> <div class="search-container" style="margin-bottom: 20px; padding: 10px; background-color: #f5f7fa; border-radius: 4px;"> <el-row :gutter="20"> ${searchFields.map((field) => ` <el-col :span="${colSpan}"> <el-input v-model="query.${field.field}" placeholder="${field.placeholder || `请输入${field.label || ''}`}" clearable ></el-input> </el-col>`).join('\n')} </el-row> <div style="margin-top: 10px;"> <el-button @click="handleSearch" type="primary">查询</el-button> <el-button @click="resetSearch" style="margin-left: 10px;">重置</el-button> </div> </div>`; } // 4. 生成表格列模板(修复属性绑定,统一缩进) const tableColumnsTemplate = columns.map(column => String.raw` <el-table-column :prop="${JSON.stringify(column.prop)}" :label="${JSON.stringify(column.label || '')}" :width="${column.width ? JSON.stringify(column.width) : '""'}" :sortable="true" :align="${JSON.stringify(column.align || 'left')}" :header-align="${JSON.stringify(column.align || 'left')}" :visible="${column.visible ?? true}" ></el-table-column>`).join(''); // 5. 构建完整组件代码(核心:彻底处理template的嵌套转义) const componentCode = String.raw`// 动态生成的表格组件 - ${componentId} import createExportMixin from './mixins/export-mixin.js'; import axios from 'axios'; // 确保导入axios // 创建mixin实例 const exportMixin1 = createExportMixin(); Vue.component('${componentId}', { mixins: [exportMixin1], data() { return { tableData: [], currentPage: 1, pageSize: 10, total: 0, // 查询条件 ${queryData} // 排序相关配置 sortField: '', sortOrder: '', // 列配置信息 columns: ${columnsConfig}, // 列设置对话框显示状态 columnSettingDialogVisible: false, // 账套信息 accountId: '${accountId}', year: '${year}', tableName: '${tableName || '数据表格'}' }; }, mounted() { this.fetchTableData(); }, methods: { /** * 查询数据方法 */ handleSearch() { console.log('查询按钮被点击,查询条件:', this.query); this.currentPage = 1; this.fetchTableData(); }, /** * 重置查询条件方法 */ resetSearch() { // 重置查询条件 ${hasSearch && searchFields.length > 0 ? `this.query = { ${searchFields.map(field => ` ${field.field}: ''`).join(',\n')} };` : ''} this.currentPage = 1; this.fetchTableData(); }, /** * 处理表格排序变化 */ handleSortChange({ prop, order }) { this.sortField = prop; this.sortOrder = order; this.fetchTableData(); }, /** * 获取表格数据方法 */ fetchTableData() { console.log('获取表格数据:', this.tableName); const params = { page: this.currentPage, page_size: this.pageSize, table_name: this.tableName, account_id: this.accountId, year: this.year }; // 添加查询条件 ${hasSearch && searchFields.length > 0 ? searchFields.map(field => ` if (this.query.${field.field}?.trim()) { params['${field.field}'] = this.query.${field.field}.trim(); }`).join('') : ''} // 添加排序参数 if (this.sortField && this.sortOrder) { params.order_field = this.sortField; params.order_direction = this.sortOrder === 'ascending' ? 'asc' : 'desc'; } // 发送请求 axios.get('/api/generic/query/', { params }) .then(response => { this.tableData = response.data?.data || []; this.total = response.data?.count || 0; }) .catch(error => { console.error('获取表格数据失败:', error); this.tableData = []; this.total = 0; if (this.$message) { this.$message.error('获取表格数据失败,请重试'); } }); }, /** * 处理每页条数变化 */ handleSizeChange(size) { this.pageSize = size; this.fetchTableData(); }, /** * 处理当前页码变化 */ handleCurrentChange(current) { this.currentPage = current; this.fetchTableData(); }, /** * 实现导出mixin所需的接口方法 */ getExportData() { const exportData = this.tableData.map(item => { const row = {}; ${columns.map(column => ` row['${column.label || ''}'] = item['${column.prop}'] ?? '';`).join('')} return row; }); // 设置列宽 const columnWidths = [ ${columns.map(column => ` {wch: ${column.width ? Math.floor(parseInt(column.width) / 7) : 15}}`).join(',')} ]; return { data: exportData, columnWidths: columnWidths, sheetName: '${tableName || '表格'}数据' }; }, /** * 打印表格方法 */ printTable() { const printWindow = window.open('', '_blank'); if (!printWindow) { if (this.$message) { this.$message.warning('请允许弹窗以完成打印操作'); } return; } const tableHtml = this.$el?.querySelector('.el-table')?.outerHTML || '<div>无表格数据</div>'; // 内部模板字符串用转义,避免与外层冲突 const printContent = ` <!DOCTYPE html> <html> <head> <title>打印表格</title> <link rel="stylesheet" href="../../lib/element-ui.css"> <style> @media print { body { padding: 20px; } .el-table { width: 100% !important; border-collapse: collapse; } .el-table th, .el-table td { padding: 8px !important; border: 1px solid #ddd !important; } .el-table__header-wrapper th, .el-table__body-wrapper td { border: 1px solid #ddd !important; } } </style> </head> <body> ${tableHtml} <script> window.print(); setTimeout(() => window.close(), 100); </script> </body> </html> `; printWindow.document.open(); printWindow.document.write(printContent); printWindow.document.close(); }, /** * 预览表格方法 */ previewTable() { const previewWindow = window.open('', '_blank'); if (!previewWindow) { if (this.$message) { this.$message.warning('请允许弹窗以完成预览操作'); } return; }, const tableHtml = this.$el?.querySelector('.el-table')?.outerHTML || '<div>无表格数据</div>'; // 内部模板字符串用转义 const previewContent = ` <!DOCTYPE html> <html> <head> <title>预览表格</title> <link rel="stylesheet" href="../../lib/element-ui.css"> <style> body { padding: 20px; font-family: Arial, sans-serif; } .el-table { width: 100% !important; } .el-table th, .el-table td { padding: 8px !important; } .preview-controls { position: fixed; top: 10px; right: 10px; background: white; padding: 10px; box-shadow: 0 0 10px rgba(0,0,0,0.1); z-index: 9999; } </style> </head> <body> <div class="preview-controls"> <button onclick="window.print()" style="padding: 5px 10px; margin-right: 10px;">打印</button> <button onclick="window.close()" style="padding: 5px 10px;">关闭</button> </div> ${tableHtml} </body> </html> `; previewWindow.document.open(); previewWindow.document.write(previewContent); previewWindow.document.close(); }, /** * 打开列设置对话框 */ openColumnSettingDialog() { this.columnSettingDialogVisible = true; }, /** * 关闭列设置对话框 */ closeColumnSettingDialog() { this.columnSettingDialogVisible = false; }, /** * 切换列显示状态 */ toggleColumnVisibility(prop, visible) { const column = this.columns.find(col => col.prop === prop); if (column) { column.visible = visible; } }, /** * 重置列显示状态 */ resetColumnSettings() { this.columns.forEach(column => { column.visible = true; }); }, /** * 更新列对齐方式 */ updateColumnAlign(prop, align) { const column = this.columns.find(col => col.prop === prop); if (column) { column.align = align; } }, /** * 获取汇总数据 */ getSummaries(param) { const { columns, data } = param; const sums = []; columns.forEach((column, index) => { if (index === 0) { sums[index] = '合计'; return; } // 只对数字类型字段进行汇总 const values = data.map(item => Number(item[column.property])); const validValues = values.filter(val => !isNaN(val)); if (validValues.length > 0) { sums[index] = validValues.reduce((prev, curr) => { const value = Number(curr); return !isNaN(value) ? prev + value : prev; }, 0).toFixed(2); } else { sums[index] = ''; } }); return sums; } }, template: ` <div class="${componentId}"> ${searchTemplate} <div class="table-container" style="overflow-x: auto; overflow-y: auto; margin-bottom: 20px; min-width: 100%; max-height: 600px;"> <el-table style="min-width: 100%; white-space: nowrap;" border stripe :data="tableData" show-summary :summary-method="getSummaries" @sort-change="handleSortChange" :sort-orders="['ascending', 'descending', null]" > ${tableColumnsTemplate} </el-table> </div> <!-- 分页组件 --> <div class="pagination-container" style="margin-top: 20px; text-align: right;"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[5, 10, 20, 50]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total" ></el-pagination> </div> <!-- 操作按钮区域 --> <div style="margin-top: 10px;"> <el-button @click="openExportDialog" type="primary" icon="el-icon-download" style="margin-left: 10px;">导出</el-button> <el-button @click="previewTable" type="primary" icon="el-icon-view" style="margin-left: 10px;">打印预览</el-button> <el-button @click="printTable" type="primary" icon="el-icon-printer" style="margin-left: 10px;">打印</el-button> <el-button @click="openColumnSettingDialog" type="primary" icon="el-icon-s-grid" style="margin-left: 10px;">列设置</el-button> </div> <!-- 列设置对话框 --> <el-dialog title="列设置" :visible.sync="columnSettingDialogVisible" width="400px" @close="closeColumnSettingDialog" > <div style="max-height: 300px; overflow-y: auto;"> <div v-for="column in columns" :key="column.prop" style="margin-bottom: 10px;"> <el-checkbox v-model="column.visible" @change="(val) => toggleColumnVisibility(column.prop, val)" > {{ column.label || column.prop || '未知列' }} </el-checkbox> <div v-if="column.visible" style="margin-top: 5px; margin-left: 25px;"> <el-select v-model="column.align" placeholder="对齐方式" size="small" style="width: 120px;" @change="(val) => updateColumnAlign(column.prop, val)" > <el-option label="左对齐" value="left"></el-option> <el-option label="居中" value="center"></el-option> <el-option label="右对齐" value="right"></el-option> </el-select> </div> </div> </div> <div slot="footer" class="dialog-footer"> <el-button @click="resetColumnSettings">重置</el-button> <el-button @click="closeColumnSettingDialog">确定</el-button> </div> </el-dialog> </div> ` }); `; // 外层componentCode的闭合 return componentCode; } } // 导出类 export default DynamicTableGenerator;
最新发布
09-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值