Vue3 + Element Plus 封装公共表格组件(带源码)

文章目录

    • 1 前言
    • 2 功能
    • 3 实现步骤
      • 3.1 复制基本表格
      • 3.2 支持自动获取表格数据
      • 3.3 支持数据列配置及插槽
        • 3.3.1 自动生成列
        • 3.2.2 支持表头自定义及插槽
        • 3.2.3 支持单元格自定义及插槽
      • 3.3 支持操作列配置及插槽
      • 3.4 支持多选框配置
      • 3.5 支持表尾配置及插槽
      • 3.6 支持分页显示
    • 4 使用方法
    • 5 源码

1 前言

由于项目中有很多菜单都是列表数据的展示,为避免太多重复代码,故将 Element Plus 的 Table 表格进行封装,实现通过配置展示列表数据

2 功能

在这里插入图片描述

  1. 支持自动获取表格数据
  2. 支持数据列配置及插槽
  3. 支持操作列配置及插槽
  4. 支持多选框配置
  5. 支持表尾配置及插槽
  6. 支持分页显示

3 实现步骤

3.1 复制基本表格

到 Element Plus官网复制一份最简单的 Table 代码,并删除多余代码

  
    
    
    
    
    
    
    
      
        Detail
      
    
  



const tableData = [
  {
    date: '2016-05-03',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
    tag: 'Home'
  },
  {
    date: '2016-05-02',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
    tag: 'Office'
  },
  {
    date: '2016-05-04',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
    tag: 'Home'
  },
  {
    date: '2016-05-01',
    name: 'Tom',
    state: 'California',
    city: 'Los Angeles',
    address: 'No. 189, Grove St, Los Angeles',
    zip: 'CA 90036',
    tag: 'Office'
  }
]

const handleClick = () => {
  console.log('click')
}

3.2 支持自动获取表格数据

tableData 数据改为从 props.api 接口获取

在这里插入图片描述

3.3 支持数据列配置及插槽

3.3.1 自动生成列

数据列(除多选框与操作列外)通过 props.columns 自动生成

在这里插入图片描述


interface TableConfigInterface {
  api: string // 表格数据获取接口
  columns: {
    // 显示列
    prop: string // 键名
    label?: string // 表头显示名称
    formatter?: (row: unknown) => string // 自定义单元格格式化方法,参数为当前行数据
    tooltip?: string // 表头 tooltip
    sortable?: boolean // 是否可以排序
    width?: number | string // 宽度
    style?: string // 单元格样式
    labelStyle?: string // 表头样式
  }[]
}
3.2.2 支持表头自定义及插槽
  • el-table-column 使用 自定义表头
  • 支持插槽
  • labelStyle 支持样式自定义
  • 支持 tooltip
  
    
      
        {{ item.label }}
        
          
        
      
    
  

3.2.3 支持单元格自定义及插槽
  • el-table-column 使用 自定义单元格
  • 支持插槽
  • style 属性支持自定义样式
  • formatter 方法支持自定义显示内容
  
    
      
        {{ item.label }}
        
          
        
      
    
  
  
    
      
        {{ item.formatter(scope.row) }}
        {{ scope.row[item.prop] }}
      
    
  

3.3 支持操作列配置及插槽

  • el-table-column 使用 自定义操作列
  • 支持插槽
  • visible 方法支持自定义按钮显示逻辑
  
    
      
        
          
          {{ item.text }}
        
      
    
  

// 操作框逻辑
const setVisible = (row: unknown, visible?: (row: unknown) => boolean) => {
  if (!visible || visible(row)) {
    return true
  }
  return false
}

3.4 支持多选框配置

增加 selection 列


TableConfigInterface 增加 rowKey、selectable

interface TableConfigInterface {
  // ......
  rowKey?: string // 行数据的 Key
  selectable?: boolean | ((row: unknown) => boolean) // 当前行多选框是否可以勾选,参数为当前行数据,默认为 false
} 

const props = withDefaults(defineProps(), {
  rowKey: 'id',
})

// 多选框逻辑
const disabledList = reactive([]) // 禁止勾选的数据
const showSelectBox = computed(() => props.selectable && disabledList.length  {
  const selectable =
    typeof props.selectable === 'boolean' ? props.selectable : props.selectable?.(row)
  if (!selectable && !disabledList.includes(row?.[props.rowKey])) {
    disabledList.push(row?.[props.rowKey])
  }
  return selectable
}

3.5 支持表尾配置及插槽

  • 增加 @selection-change 及 ref 配置
  • 支持插槽
  • visible 方法支持自定义按钮显示逻辑
  


  
  
    
      
        
        {{ item.text }}
      
    
  

const tableRef = ref()
const isSelected = ref(false) // 是否有选中数据
const selectionRows = ref([]) // 当前选中的数据
const handleSelectionChange = (rows: unknown[]) => {
  selectionRows.value = rows
  isSelected.value = rows.length > 0
}
const indeterminate = computed(
  () =>
    selectionRows.value.length > 0 &&
    selectionRows.value.length < tableData.length - disabledList.length
)

3.6 支持分页显示

最底部增加


interface TableConfigInterface {
  // ......
  layout?: string // 组件布局
} 

const pagination = ref({
  currentPage: 1,
  pageSize: 10
})

4 使用方法

  
    
      姓名
    
    
      Yana
    
  



const tableConfig: TableConfigInterface = {
  api: 'getTableData',
  columns: [
    {
      prop: 'date',
      label: 'Date',
      tooltip: 'This is Date'
    },
    {
      prop: 'name',
      label: 'Name'
    },
    {
      prop: 'state',
      label: 'State'
    },
    {
      prop: 'city',
      label: 'City'
    },
    {
      prop: 'address',
      label: 'Address'
    },
    {
      prop: 'zip',
      label: 'Zip',
      style: 'color: red',
      labelStyle: 'color: red',
      sortable: true
    }
  ],
  operation: {
    columns: [
      {
        text: '编辑',
        click: () => {},
        visible: (row) => row.date === '2016-05-07'
      }
    ]
  },
  rowKey: 'date',
  selectable: (row) => row.date === '2016-05-07',
  footer: {
    operations: [
      {
        text: '删除',
        click: () => {}
      }
    ]
  }
}

5 源码

  
    
      
      
        
          
            
              {{ item.label }}
              
                
              
            
          
        
        
          
            
              {{ item.formatter(scope.row) }}
              {{ scope.row[item.prop] }}
            
          
        
      
      
        
          
            
              
                
                {{ item.text }}
              
            
          
        
      
    
    
      
      
        
          
            
            {{ item.text }}
          
        
      
    
  
  



interface OperationInterface {
  click: (row: unknown) => void // 按钮点击方法,参数为当前行数据
  text?: string // 按钮显示文字
  icon?: string // 按钮 icon
  visible?: (row?: unknown) => boolean // 设置按钮是否可见,参数为当前行数据,默认为 true
  type?: string // 按钮类型['primary'| 'success'| 'warning'| 'danger'| 'info']
  link?: boolean // 是否为链接按钮
  plain?: boolean // 是否为朴素按钮
}
interface TableConfigInterface {
  api: string // 表格数据获取接口
  rowKey?: string // 行数据的 Key
  columns: {
    // 显示列
    prop: string // 键名
    label?: string // 表头显示名称
    formatter?: (row: unknown) => string // 自定义单元格格式化方法,参数为当前行数据
    tooltip?: string // 表头 tooltip
    sortable?: boolean // 是否可以排序
    width?: number | string // 宽度
    style?: string // 单元格样式
    labelStyle?: string // 表头样式
  }[]
  selectable?: boolean | ((row: unknown) => boolean) // 当前行多选框是否可以勾选,参数为当前行数据,默认为 false
  operation?: {
    // 操作列
    columns: OperationInterface[]
    width?: number | string // 宽度
  }
  footer?: {
    // 操作列
    operations: OperationInterface[]
  }
  defaultSort?: {
    // 默认排序
    prop: string // 默认排序的列
    order?: string // ['ascending'| 'descending'], 没有指定 order, 则默认顺序是 ascending
  }
  maxHeight?: number | string // 表格最大高度
  layout?: string
}

const props = withDefaults(defineProps(), {
  rowKey: 'id',
  layout: 'prev, pager, next, total'
})
const pagination = ref({
  currentPage: 1,
  pageSize: 10
})
const tableRef = ref()
let tableData = reactive([])

// 多选框逻辑
const isSelected = ref(false) // 是否有选中数据
const selectionRows = ref([]) // 当前选中的数据
const handleSelectionChange = (rows: unknown[]) => {
  selectionRows.value = rows
  isSelected.value = rows.length > 0
}
const disabledList = reactive([]) // 禁止勾选的数据
const setSelectable = (row: unknown) => {
  const selectable =
    typeof props.selectable === 'boolean' ? props.selectable : props.selectable?.(row)
  if (!selectable && !disabledList.includes(row?.[props.rowKey])) {
    disabledList.push(row?.[props.rowKey])
  }
  return selectable
}
const indeterminate = computed(
  () =>
    selectionRows.value.length > 0 &&
    selectionRows.value.length  props.selectable && disabledList.length  boolean) => {
  if (!visible || visible(row)) {
    showOperation.value = true
    return true
  }
  return false
}

// 排序
const handleSortChange = (data: { prop: string; order: string | null }) => {
  const { prop, order } = data
  console.log(prop, order)
  // getTableData
}

// 跳转详情页
const goDetail = (row: unknown) => {
  console.log(row)
}

// 发送接口
const loading = ref(true)
const getTableData = () => {
  loading.value = true
  showOperation.value = false
  tableData = [
    {
      date: '2016-05-02',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-03',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-04',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-05',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-06',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-07',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-08',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-09',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-10',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    },
    {
      date: '2016-05-11',
      name: 'Tom',
      state: 'California',
      city: 'Los Angeles',
      address: 'No. 189, Grove St, Los Angeles',
      zip: 'CA 90036'
    }
  ]
  loading.value = false
}
getTableData()



.table-wrapper {
  border-top: 1px solid #eaeaea;
  border-left: 1px solid #eaeaea;
  border-right: 1px solid #eaeaea;
}
.inline-flex {
  display: inline-flex;
  align-items: center;
}
.p-14 {
  border-bottom: 1px solid #eaeaea;
  padding: 14px;
}
.p-y-20 {
  padding-top: 20px;
  padding-bottom: 20px;
  justify-content: center;
}



.table-tooltip {
  max-width: 220px;
}

本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/0bdcf6f47c.html