前言  

在Vue的Ant-Design-Of-Vue-Table组件中,你可以对ant-design-of-vue-Table-pagination组件进行二次封装,这样可以减少页面代码重复,使页面代码更简洁、更容易操作。      

1.新建一个table.js文件(Table+Pagination+查询按钮+重置按钮二次封装)   

import { Table } from 'ant-design-vue'
import Vue from 'vue'
const componentName = 'my-table-option'
export default {
  name: 'myTable',
  props: Object.assign({}, Table.props, {
    // 返回 Promise<{ currPage, totalCount, list: any[] }> 的获取数据的函数,用于内部管理数据加载
    data: { type: Function },
    // 查询条件
    dataParameters: null,
    // 是否开启:单击行则选中行
    selectOnClick: { type: Boolean, default: true },
    // 默认翻到第 1 页
    pageNum: { type: Number, default: 1 },
    // 默认分页大小 10 行
    pageSize: { type: Number, default: 10 },
    // 是否显示分页大小切换下拉框
    showSizeChanger: { type: Boolean, default: true },
    // 是否显示分页器
    showPagination: { type: [String, Boolean], default: 'auto' },
    pageURI: { type: Boolean, default: false },
    bordered: { type: Boolean, default: true }
  }),
  data () {
    return {
      localLoading: false,
      localDataSource: [],
      localPagination: Object.assign({}, this.pagination),
      localScroll: {},

      // 表格列显示隐藏
      filterValue: [],
      filterShow: false,
      fullDataSource: null, //合计
    }
  },
  computed: {
    // 判断是否在弹出框里,用于定义表格是否可以滚动
    isInDialog () {
      let parent = this.$parent
      while (parent) {
        if (parent.$options._componentTag === 'a-modal') {
          return true
        }
        parent = parent.$parent
      }
      return false
    },

    localKeys () {
      return [...Object.keys(this.$data), ...Object.keys(this._computedWatchers), ...Object.keys(this).filter(k => k.startsWith('local'))]
    },

    // 处理最大显示长度后的列
    allColumns () {
      let results = []
      // 设置 scroll 属性后,需要设置所有列的 width 来避免表头和内容的错位。
      // 对未设置 width 的 col 设置平均宽度
      const fullWidth = this.localScroll.x || (this.$el || {}).offsetWidth - 85
      const remainWidth = this.columns.reduce(
        (remain, { width }) => width
          ? typeof width === 'string' && width.endsWith('%')
            ? remain - parseFloat(width) * fullWidth / 100
            : remain - parseFloat(width)
          : remain,
        fullWidth
      )
      const noWidthColCount = this.columns.reduce((count, { width }) => width ? count : count + 1, 0)
      const averageWidth = remainWidth / noWidthColCount
      this.columns.forEach(col => !col.width && Vue.set(col, 'width', averageWidth))

      results = this.columns.reduce((results, col) => {
        // 超出后显示省略号
        if (this.isDrag || col.key !== 'action') {
          // 组件不支持排序省略一起使用,使用排序后,表头省略会失效
          col.ellipsis = true
        }
        const result = Object.assign({}, col)
        results.push(result)
        return results
      }, results)

      return results
    },
    localColumns () {
      return this.allColumns.filter(col => this.filterValue.includes(col.dataIndex || col.key || col.title))
    },
    // 不支持表格中有子表格,需要屏蔽
    localComponents () {
      const headerComponent = {}
      if (!this.isDrag) return headerComponent
      headerComponent.header = {}
      headerComponent.header.cell = (h, props, children) => {
        const { key, ...restProps } = props
        const col = this.columns.find(col => {
          const k = col.dataIndex || col.key
          return k === key
        })
        if (!col) {
          return h('th', { ...restProps }, [...children])
        }
        const dragProps = {
          key: col.dataIndex || col.key,
          class: 'table-draggable-handle',
          attrs: {
            w: 8,
            x: col.width,
            z: 1,
            axis: 'x',
            draggable: true,
            resizable: false
          },
          on: {
            dragging: (x) => {
              col.width = Math.max(x, 35)
            }
          }
        }
        const drag = h('vue-draggable-resizable', { ...dragProps })
        return <th {...restProps} title={col.title} width={col.width} class="resize-table-th">
          {children}
          {drag}
        </th>
      }
      return headerComponent
    }
  },
  watch: {
    loading (val) {
      this.localLoading = val
    },
    // 表格源数据
    dataSource: {
      handler (val) {
        this.localDataSource = val
      },
      immediate: true
    },
    'localPagination.current' (val) {
      this.pageURI && this.$router.push({
        ...this.$route,
        params: Object.assign({}, this.$route.params, { pageNo: val })
      })
    },
    pageNum (val) {
      Object.assign(this.localPagination, { current: val })
    },
    pageSize (val) {
      Object.assign(this.localPagination, { pageSize: val })
    },
    showSizeChanger (val) {
      Object.assign(this.localPagination, { showSizeChanger: val })
    },
    scroll () {
      this.calcLocalScroll()
    },
  },
  created () {
    // 判断表格使传进来得是获取数据得方法还是数据数组
    if (this.data) {
      const { pageNo } = this.$route.params
      const localPageNum = this.pageURI ? (pageNo && parseInt(pageNo)) : this.pageNum
      this.localPagination = ['auto', true].includes(this.showPagination)
        ? Object.assign({}, this.localPagination, {
          showQuickJumper: true,
          current: localPageNum,
          pageSize: this.pageSize,
          showSizeChanger: this.showSizeChanger,
          pageSizeOptions: ['10', '20', '40']
        })
        : false
      this.loadData()
    } else {
      this.localPagination = false
    }

    window.addEventListener('resize', this.calcLocalScroll)
  },
  mounted () {
    setTimeout(() => {
      // this.calcLocalScroll()
      this.resetColumns()
    })
  },
  destroyed () {
    window.removeEventListener('resize', this.calcLocalScroll)
  },
  methods: {
    /**
     * 表格重新加载方法
     * 如果参数为 true, 则强制刷新到第一页
     * @param {boolean} bool
     */
    refresh (bool = false, isSearch = true) {
      !isSearch && this.resetColumns()
      bool && (this.localPagination = Object.assign({}, {
        current: 1,
        pageSize: this.pageSize
      }))
      this.loadData()
    },
    /**
  * 表格查询方法
  * 如果参数为 true, 则强制刷新到第一页
  * @param {boolean} bool
  */
    serarch () {
      this.loadData()
    },
    /**
     * 加载数据方法
     * @param {{ pageNum: number, pageSize: number }} pagination 分页选项器
     * @param {{ [field: string]: string }} filters 过滤条件
     * @param {{ field: string, order: 'asc' | 'desc' }} sorter 排序条件
     */
    loadData (pagination, filters, sorter = {}) {
      this.localLoading = true

      let dataParameters = this.dataParameters;
      let extraParams = {};
      if (dataParameters != null) {
        if (
          typeof dataParameters != "object" ||
          Array.isArray(dataParameters)
        ) {
          extraParams = dataParameters;
        } else {
          for (let i in dataParameters) {
            let source = extraParams[i];
            if (typeof source == "function") {
              extraParams[i] = dataParameters[i]();//函数,调用
            } else {
              extraParams[i] = dataParameters[i];
            }
          }
        }
      }
      const result = this.data({
        pageNum: (pagination && pagination.current) ||
          this.showPagination && this.localPagination.current || this.pageNum,
        pageSize: (pagination && pagination.pageSize) ||
          this.showPagination && this.localPagination.pageSize || this.pageSize,

        sidx: sorter.field,
        order: sorter.order && sorter.order.slice(0, sorter.order.length - 3),

        ...filters,
        ...extraParams
      })

      // 对接自己的通用数据接口需要修改下方代码中的 r.pageNum, r.totalCount, r.list
      // eslint-disable-next-line
      if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') {
        result.then(r => {
          r = r || { pageNum: 1, total: 0, list: [] }
          this.localPagination = this.showPagination
            ? Object.assign({}, this.localPagination, {
              showQuickJumper: true,
              current: r.data.pageNum, // 返回结果中的当前分页数
              total: r.data.total, // 返回结果中的总记录数
              showSizeChanger: this.showSizeChanger,
              pageSize: (pagination && pagination.pageSize) || this.localPagination.pageSize
            })
            : false
          // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
          if (r.data.list.length === 0 && this.showPagination && this.localPagination.current > 1) {
            this.localPagination.current--
            this.loadData()
            return
          }

          // 这里用于判断接口是否有返回 r.totalCount 且 this.showPagination = true 且 pageNo 和 pageSize 存在 且 totalCount 小于等于 pageNo * pageSize 的大小
          // 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能
          try {
            if ((['auto', true].includes(this.showPagination) && r.totalCount <= (r.pageNo * this.localPagination.pageSize))) {
              this.localPagination.hideOnSinglePage = true
            }
          } catch (e) {
            this.localPagination = false
          }
          console.log('查看新数据返回', r.data)
          this.fullDataSource = r.data;
          this.localDataSource = r.data.list // 返回结果中的数组数据
          this.localLoading = false
        })
      }
    },
    /**
     * 自定义行。可以配置表格行的相关事件,此处主要定义表格单击选中行,没有复选框或者单选框得表格可以屏蔽该功能
     * @param {*} record 
     */
    localCustomRow (record) {
      const rowCustomer = this.customRow ? this.customRow(record) : {}

      if (!this.selectOnClick || !this.rowSelection) {
        return rowCustomer
      }

      if (!rowCustomer.on) {
        rowCustomer.on = {}
      }
      // 单击选中行需要判断是单选框还是多选框,表格多选或单选框得使用会在后续发文章补充。
      const selectOnClickHandler = () => {
        const { type, selectedRowKeys } = this.rowSelection
        if (selectedRowKeys.includes(record[this.rowKey]) && !type) {
          this.rowSelection.selections.splice(this.rowSelection.selections.findIndex(r => r === record), 1)
          selectedRowKeys.splice(selectedRowKeys.findIndex(r => r === record[this.rowKey]), 1)
        } else if (!type) {
          this.rowSelection.selections.push(record)
          selectedRowKeys.push(record[this.rowKey])
        } else {
          this.rowSelection.selectedRow = record
          selectedRowKeys.splice(0, 1, record[this.rowKey])
        }
      }
      if (rowCustomer.on.click) {
        const originalClickHandler = rowCustomer.on.click
        rowCustomer.on.click = e => {
          originalClickHandler(e)
          selectOnClickHandler(e, record)
        }
      } else {
        rowCustomer.on.click = selectOnClickHandler
      }
      return rowCustomer
    },
    /**
    * 表格列动态显示隐藏方法
    */
    filter (checkedValues) {
      this.filterValue = checkedValues
    },
    /**
     * 表格列重置,主要使用在数据使用数据数组的表格
     */
    resetColumns () {
      this.filterValue = this.allColumns.map(col => col.dataIndex || col.key || col.title)
      this.filterShow = !this.filterShow
    },
  },
  // 渲染表格方法
  render (h) {
    const props = {}
    // 表格属性
    Object.keys(Table.props).forEach(k => {
      const localKey = `local${k.substring(0, 1).toUpperCase()}${k.substring(1)}`
      // if(k === 'columns'){}
      if (this.localKeys.includes(localKey)) {
        props[k] = this[localKey]
      } else if (this[k] != null) {
        props[k] = this[k]
      }
    })
    // 
    const on = { ...this.$listeners }
    this.data && (on.change = this.loadData)


    let { title, footer } = this;
    const {
      title: slotTitle,
      reduce: slotReduce,
    } = this.$scopedSlots;

    const footerFunction = () => { return slotReduce(this.fullDataSource); };
    title = title || slotTitle;
    footer = footer || footerFunction;

    props.title = title;
    props.footer = footer;

    return (
      <div class={`${componentName}-wrapper`} style="position: relative;">{[
        h('a-table', {
          props,
          on,
          scopedSlots: { ...this.$scopedSlots }
        },
          Object.keys(this.$slots).map(name => (
            <template slot={name}>{this.$slots[name]}</template>
          ))
        )]}
      </div>
    )
  }
}

2.vue页面引入自定义封装方法(引入table.js文件)     

 

<template>
  <div>
    <!-- 搜索 -->
    <a-row>
      <a-form :model="searchParam" ref="form">
        <a-row>
          <a-col span="8">
            <span>航线代码:</span>
            <a-input
              style="width: 70%"
              v-model="searchParam.routeCode"
              placeholder="航线代码"
            />
          </a-col>

          <a-col span="8">
            <span>航线名称:</span>
            <a-input
              style="width: 70%"
              v-model="searchParam.routeName"
              placeholder="航线名称"
            />
          </a-col>
        </a-row>
        <br />
        <a-row>
          <a-col span="2">
            <a-button type="primary" title="查询" @click="Search"
              >查询</a-button
            >
          </a-col>
          <a-col span="2">
            <a-button title="重置" @click="query">重置</a-button>
          </a-col>
          <a-col span="2">
            <a-popconfirm
              title="确定删除?"
              ok-text="确定"
              cancel-text="取消"
              @confirm="confirm"
              @cancel="cancel"
            >
              <a-button title="删除" :disabled="!hasSelected" type="danger"
                >删除</a-button
              >
            </a-popconfirm>
          </a-col>
        </a-row>
      </a-form>
    </a-row>
    <a-row>
      <!-- 表格 -->
      <s-table
        ref="table"
        :columns="columns"
        :data="loadData"
        :dataParameters="searchParam"
      >
        <template slot="reduce" slot-scope="currentPageData">
          共有{{ currentPageData && currentPageData.total }}条数据
        </template>
      </s-table>
    </a-row>
  </div>
</template>

<script>
// 引用数据请求方法
import api from '@/api'
// 引用封装的table和pagation方法
import STable from './tables'
export default {
  data() {
    return {
      // table表头
      columns: [
        {
          title: '类型',
          dataIndex: 'type',
          align: 'center',
          width: '20%',
        },
        {
          title: '航线名称',
          dataIndex: 'routeName',
          align: 'center',
          width: '20%',
        },
        {
          title: '航线代码',
          dataIndex: 'routeCode',
          align: 'center',
          width: '20%',
        },
        {
          title: '备注',
          dataIndex: 'remark',
          align: 'center',
          width: '20%',
        },
        {
          title: '操作',
          width: '10%',
          align: 'center',
          scopedSlots: { customRender: 'operation' },
        },
      ],
      // 查询条件
      searchParam: {
        routeCode: null,
        routeName: null,
      },
    }
  },
  methods: {
    /*
     * 获取数据的方法
     * */
    loadData(pagination) {
      // 请求列表接口
      return api.routesMaintenanceList({ ...pagination })
    },
    /*
     * 重置按钮对应的方法
     * */
    query() {
      this.refresh(true)
    },
    refresh(isBackToFirstPage = false) {
      this.searchParam = {
        routeCode: null,
        routeName: null,
      }
      this.selectedRowKeys = []
      this.$refs.table.refresh(isBackToFirstPage)
    },
    /*
     * 查询
     * */
    Search() {
      this.refresh(false)
    }
  },
}
</script>

<style scoped></style>