Vue3+Vite+TypeScript+Element Plus开发-27.表格页码自定义

系列文章

Vue3+Vite+TypeScript+Element Plus开发https://blog.csdn.net/sen_shan/category_12933362.html

26.Element-Plus 表单校验的"配置化封装 + 自定义插件入口"https://blog.csdn.net/sen_shan/article/details/154388514

文章目录

目录

系列文章

文章目录

前言

配置文件

组件

客制表格


前言

本系列文章介绍了基于Vue3+Vite+TypeScript+ElementPlus的表单校验配置化封装方案。

文章详细讲解了如何通过.env文件配置分页参数(VITE_APP_TABLE_CURRENT_PAGE等),并实现config/index.ts中的类型转换工具(toNumber/toArray)。

核心组件ActionTableCont.vue展示了带分页功能的表格实现,包括动态列渲染、分页控制和选中项处理。

同时演示了如何通过CustomTable组件进行客制化表格开发,集成权限控制和按钮组功能。文章提供了一套完整的表单校验配置方案,便于在项目中复用和扩展。

本次修改细节蛮多,直接贴出源代码供参考。

配置文件

1..evn、.env.development文件

复制代码
VITE_APP_TABLE_CURRENT_PAGE=1
VITE_APP_TABLE_PAGE_SIZE=10
VITE_APP_TABLE_PAGE_SIZES=[10,20,50,100]

表格默认页码,从 1 开始计数

VITE_APP_TABLE_CURRENT_PAGE=1

表格每页默认条数

VITE_APP_TABLE_PAGE_SIZE=10

表格"每页条数"下拉可选项,JSON 数组格式,**必须用双引号**

VITE_APP_TABLE_PAGE_SIZES=[10,20,50,100]

2.config文件修改

修改config\index.ts文件

TypeScript 复制代码
// config/index.ts
// 对于数字类型的转换,可以创建类似的方法:
const toNumber = (value: string | undefined, defaultValue: number): number => {
  const parsed = Number(value);
  return isNaN(parsed) ? defaultValue : parsed;
};

const toArray = (value: string | undefined, defaultValue: number[]): number[] => {
  if (!value) return defaultValue;
  try {
    const parsed = JSON.parse(value);
    return Array.isArray(parsed) ? parsed.map(Number) : defaultValue;
  } catch {
    return defaultValue;
  }
};
const config = {
    // API 地址
    apiBaseUrl: import.meta.env.VITE_APP_API_URL || 'https://default.example.com/api',
    apiKey: import.meta.env.VITE_APP_API_KEY || '',
        // 应用示例:
    tableCurrentPage : toNumber(import.meta.env.VITE_APP_TABLE_CURRENT_PAGE, 1),
    tablePageSize : toNumber(import.meta.env.VITE_APP_TABLE_PAGE_SIZE, 10),
    tablePageSizes: toArray(import.meta.env.VITE_APP_TABLE_PAGE_SIZES, [10, 20, 30, 40, 50]),
  
    // 其他配置
    featureFlags: {
      newFeature: import.meta.env.VITE_APP_FEATURE_FLAG === 'true' || false,
    },
  };
  
  export default config;
  
  1. 在 index.ts 顶部写转换器(复用现有或新建)。

  2. 在 config 对象里加键,必须 转换器(env key, 默认值) 。

  3. 在 .env.example 中给出示例值,CI 自动同步到各环境。

组件

修改components\ActionTableCont.vue文件

html 复制代码
<template>
  <div>
    <!-- 表格 -->
    <el-table
      :data="currentPageData"
      style="width: 100%"
      border
      @selection-change="handleSelectionChange"
    >
      <!-- 选择列 -->
      <el-table-column
        v-if="showSelection"
        type="selection"
        width="55"
        align="center"
      ></el-table-column>

      <!-- 序号列 -->
      <el-table-column
        type="index"
        label="序号"
        width="50"
        align="center"
      ></el-table-column>

      <!-- 动态列 -->
      <el-table-column
        v-for="column in visibleColumns"
        :key="column.field"
        :prop="column.field"
        :label="column.label"
        :width="column.width"
        :align="column.align || 'left'"
      ></el-table-column>
    </el-table>

    <!-- 分页 -->
    <el-pagination
      :current-page="currentPage"
      :page-size="pageSize"
      :page-sizes="pageSizes"
      layout="total, sizes, prev, pager, next, jumper"
      :total="tableData.length"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      style="margin-top: 20px"
    ></el-pagination>
  </div>
</template>

<script setup>
import { ref, computed, defineProps, defineEmits, watch } from 'vue';
import defaultConfig from '../../config/index.js'; // 相对路径

const props = defineProps({
  tableColumns: {
    type: Array,
    required: true,
    default: () => [],
  },
  tableData: {
    type: Array,
    required: true,
    default: () => [],
  },
  pageSize: {
    type: Number,
    default: defaultConfig.tablePageSize,// 10
  },
  pageSizes: {
    type: Array,
    default: () => defaultConfig.tablePageSizes//[5, 10, 15, 20],
  },
  showSelection: {
    type: Boolean,
    default: false,
  },
});

const emit = defineEmits(['update:currentPage', 'update:pageSize', 'selection-change']);

const currentPage = ref(defaultConfig.tableCurrentPage);

const currentPageData = computed(() => {
  const start = (currentPage.value - 1) * props.pageSize;
  const end = start + props.pageSize;
  return props.tableData.slice(start, end);
});

const visibleColumns = computed(() => {
  return props.tableColumns.filter((column) => !column.hide);
});

const handleSizeChange = (newSize) => {
  console.log(`分页大小改变,新的分页大小为: ${newSize}`);
  emit('update:pageSize', newSize);
  currentPage.value = 1; // 重置当前页为第一页
  emit('update:currentPage', currentPage.value);
};

const handleCurrentChange = (newPage) => {
  console.log(`当前页码改变,新的页码为: ${newPage}`);
  currentPage.value = newPage;
  emit('update:currentPage', currentPage.value);
};

const handleSelectionChange = (selection) => {
  emit('selection-change', selection);
};

// 监听 currentPage 和 pageSize 的变化并记录日志
watch(currentPage, (newVal, oldVal) => {
  console.log(`currentPage changed from ${oldVal} to ${newVal}`);
});

watch(() => props.pageSize, (newVal, oldVal) => {
  console.log(`pageSize changed from ${oldVal} to ${newVal}`);
});
</script>

修改重点:

1.统一把column.prop改为column.field

2.页码调整,直接从Config中带出

客制表格

html 复制代码
<template>

  <div>

    <ActionButtonGroup
        :show-add="hasPermission('demo2:create')"  
        :show-delete="true"
        :disabled-add="false"
        :disabled-edit="!selectedData.length"
        :disabled-delete="!selectedData.length"
  
        @add="handleAdd"
        @edit="handleEdit"
        @delete="handleDelete"
      />
    <!-- 表格 -->
    <CustomTable
      :tableColumns="columns"
      :tableData="data"
      :pageSize="pageSize"
      :pageSizes="[5, 10, 15, 20, 30]"
      :showSelection="true"
      @update:currentPage="currentPage = $event"
      @update:pageSize="pageSize = $event"
      @selection-change="handleSelectionChange"
    />

   

    <!-- 显示选中数据 -->
    <div v-if="selectedData.length > 0" style="margin-top: 20px">
      <h3>选中的数据:</h3>
      <pre>{{ selectedData }}</pre>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import CustomTable from '@/components/ActionTableCont.vue';
import { usePermission } from "@/utils/permissionUtils";
import ActionButtonGroup from "@/components/ActionBtnHdrCont.vue";

import {
  Plus,
  Check,
  Delete,
  Edit,
  Message,
  Search,
  Star,
  Upload,
} from '@element-plus/icons-vue'

const hasPermission = usePermission();

const columns = ref([
  {
    field: 'date',
    label: '日期',
    width: 180,
  },
  {
    field: 'name',
    label: '姓名',
    width: 180,
  },
  {
    field: 'address',
    label: '地址',
    hide: true,
  },
]);

const data = ref([
  {
    id: 1,
    date: '2025-04-14',
    name: '张三',
    address: '上海市普陀区金沙江路 1518 弄',
  },
  {
    id: 2,
    date: '2025-04-15',
    name: '李四',
    address: '上海市普陀区金沙江路 1517 弄',
  },
  {
    id: 3,
    date: '2025-04-16',
    name: '王五',
    address: '上海市普陀区金沙江路 1516 弄',
  },
  {
    id: 4,
    date: '2025-04-17',
    name: '赵六',
    address: '上海市普陀区金沙江路 1515 弄',
  },
  {
    id: 5,
    date: '2025-04-18',
    name: '孙七',
    address: '上海市普陀区金沙江路 1514 弄',
  },
  {
    id: 6,
    date: '2025-04-19',
    name: '周八',
    address: '上海市普陀区金沙江路 1513 弄',
  },
  {
    id: 7,
    date: '2025-04-20',
    name: '吴九',
    address: '上海市普陀区金沙江路 1512 弄',
  },
  {
    id: 8,
    date: '2025-04-21',
    name: '郑十',
    address: '上海市普陀区金沙江路 1511 弄',
  },
  {
    id: 9,
    date: '2025-04-22',
    name: '钱十一',
    address: '上海市普陀区金沙江路 1510 弄',
  },
  {
    id: 10,
    date: '2025-04-23',
    name: '孔十二',
    address: '上海市普陀区金沙江路 1509 弄',
  },
  {
    id: 11,
    date: '2025-04-24',
    name: '秦十三',
    address: '上海市普陀区金沙江路 1508 弄',
  },
  {
    id: 12,
    date: '2025-04-25',
    name: '尤十四',
    address: '上海市普陀区金沙江路 1507 弄',
  },
]);

const currentPage = ref(1);
const pageSize = ref(5);// 默认每页显示5条数据

// 用于存储选中的数据
const selectedData = ref([]);

// 处理选中数据变化
const handleSelectionChange = (selection) => {
  selectedData.value = selection;
};

// 获取选中数据
const handleDelete = () => {
  console.log('Selected Data:', selectedData.value);
  console.log('Selected  Data length:', selectedData.value.length);
  if (selectedData.value.length > 0) {
    // 删除逻辑
    console.log('Deleting selected data...');
    selectedData.value = [];
  } else {
    console.log('No selected data to delete.');
  }
  
};
</script>

未做调整,未来会从Config中带出。

相关推荐
醉方休2 小时前
web前端 DSL转换技术
前端
刺客_Andy2 小时前
React 第五十二节 Router中 useResolvedPath使用详解和注意事项示例
前端·react.js·架构
豆浆9452 小时前
vue3+qiankun主应用和微应用的路由跳转返回
前端
王将近2 小时前
Cesium 山洪流体模拟
前端·cesium
小时前端2 小时前
当循环遇上异步:如何避免 JavaScript 中最常见的性能陷阱?
前端·javascript
Jonathan Star2 小时前
在 JavaScript 中, `Map` 和 `Object` 都可用于存储键值对,但设计目标、特性和适用场景有显著差异。
开发语言·javascript·ecmascript
Bacon3 小时前
Electron 集成第三方项目
前端
自由日记3 小时前
css学习9
前端·css·学习