对table组件的二次封装

一、Table组件

1、封装Table组件为tableList.vue文件如下:

javascript 复制代码
<template>
  <!-- 主列表 -->
  <el-table :data='tableData' :height='tableHeight' :show-header='showHeader' stripe @expand-change="expandSelect" :expand-row-keys="expands" @cell-click="handleCellClick" empty-text='暂无数据' class='el_tab_alage' :header-cell-style="cellHeaderStyle" :row-key='getRowKeys' @selection-change="handleSelectionChange">
    <!-- 单选框 -->
    <el-table-column align="center" width="50" label="" v-if="tableSelection.key === true && tableSelection.type === 'radio'">
      <template slot-scope="scope">
        <el-radio :label="scope.$index" v-model="radio" @change="handleTemplateRow(scope.$index, scope.row)">&nbsp;</el-radio>
      </template>
    </el-table-column>
    <!-- index索引 -->
    <el-table-column label="序号" type="index" width="50" align="center" v-if="tableSelection.key === true && tableSelection.type === 'index'"></el-table-column>
    <!-- 多选框 -->
    <el-table-column type="selection" width="50" align="center" v-if="tableSelection.key === true && tableSelection.type === 'selection'"></el-table-column>
    <!-- 列表表头-->
    <el-table-column type="expand" v-if="tableSelection.key === true && tableSelection.type === 'expand'">
      <template slot-scope="scope">
        <el-form label-position="left" inline class="demo-table-expand">
          <el-form-item :label="index.label" v-for="(index, item) in tableLabel" :key='item' v-show="index.type === 'expand'">
            <span>{{scope.row[index.list]}}</span>
          </el-form-item>
        </el-form>
      </template>
    </el-table-column>
    <template v-for="(index, item) in tableLabel">
      <el-table-column fit :align='index.tableAlign ? index.tableAlign : "center"' :key='item' :sortable='index.sort' v-if="index.type !== 'expand'" :label="index.label" :width="index.width" :show-overflow-tooltip="index.overflowShow === 'hidden' ? true : false" :prop="index.list">
        <template slot-scope="scope">
          <!-- 图片 -->
          <template v-if="index.type === 'image'">
            <el-image v-if="scope.row[index.list] !== ''" style="width: 100px; height: 50px;" :src="scope.row[index.list]">
            </el-image>
            <div v-else></div>
          </template>
          <!-- 头像 -->
          <template v-else-if="index.type === 'head'">
            <el-image v-if="!(scope.row[index.list] === '' || scope.row[index.list] === null)" style="width: 50px; height: 50px;" :src="scope.row[index.list]">
            </el-image>
            <div v-else></div>
          </template>
          <!-- 按钮 -->
          <template v-else-if="index.type === 'btn'">
            <el-button type="text" @click.native.prevent="index.method(scope.row, scope)">
              <u>{{scope.row[index.list]}}</u>
            </el-button>
          </template>
          <!-- 下拉 -->
          <template v-else-if="index.type === 'select'">
            <el-select v-model="scope.row[index.list]" @change="changeType($event, scope.row, item)" size="medium">
              <el-option v-for="item in index.options" :key="item.value" :label="item.label" :value="item.value">
              </el-option>
            </el-select>
          </template>
          <!-- 开关按钮 -->
          <template v-else-if="index.type === 'switch'">
            <div v-if="index.noSwitch(scope.row)">
              <el-switch @change="index.method(scope.row, scope)" v-model="scope.row[index.list]" :inactive-value="index.offValue ? index.offValue : 'off'" :active-value="index.onValue ? index.onValue : 'on'" :inactive-text="index.offText ? index.offText : ''" :active-text="index.onText ? index.onText : ''" :inactive-color="index.offColor ? index.offColor : '#ff4949'" :active-color="index.onColor ? index.onColor : '#13ce66'"></el-switch>
            </div>
          </template>
          <!-- 内容自定义 -->
          <template v-else-if="index.type === 'html'">
            <div v-html="index.code(scope.row)" class="theHtml"></div>
          </template>
          <!-- 正常显示 -->
          <template v-else>
            <!-- {{scope.row[index.list]}} -->
            {{scope.row[index.list]?scope.row[index.list]:'-'}}
          </template>
        </template>
      </el-table-column>
    </template>
    <!-- 正常按钮操作 -->
    <el-table-column fit align='center' :label="tableOption.label" :fixed="tableOption.fixed ? tableOption.fixed : false" :width="tableOption.width" v-if="tableOption.value === 0">
      <template style="margin-left: 30px;" slot-scope="scope">
        <el-button align='right' v-for="(value, item) in tableOption.options" :key='item' v-if="value.show ? value.show(scope.row) : true" :type="value.type ? value.type : 'text'" :style="value.style ? JSON.parse(value.style) : {}" :plain='value.plain ? value.plain : false' :round='value.round ? value.round : false' :size='value.size ? value.size : "medium"' :icon="value.icon" @click.native.prevent="value.method(scope.row, scope)">{{value.label}}
        </el-button>
      </template>
    </el-table-column>
  </el-table>
</template>
<script>
export default {
  data () {
    return {
      radio: '',
      cellHeaderStyle: {
        fontSize: "16px",
        color: "#606266"
      },
      expands: [],
      getRowKeys (row) {
        return row.id
      }
    }
  },
  props: {
    tableData: {
      type: Array,
      default: () => { }
    },
    tableHeight: {
      type: Number,
      default: () => {
        return null
      }
    },
    showHeader: {
      type: Boolean,
      default: () => {
        return true
      }
    },
    tableSelection: {
      type: Object,
      default: () => {
        return {
          key: false,
          type: '',
          detaile: false
        }
      }
    },
    tableLabel: {
      type: Array,
      default: () => { }
    },
    tableOption: {
      type: Object,
      default: () => {
        return {
          value: 999
        }
      }
    }
  },

  methods: {
    handleSelectionChange (val) {
      this.$emit('onHandleSelectionChange', val)
    },
    handleTemplateRow (index, row) {
      this.$emit('onHandleTemplateRow', row)
    },
    changeType (event, row) {
      this.$emit('onChangeType', event, row)
    },
    expandSelect (row, expandedRows) {
      const that = this
      if (expandedRows.length) {
        that.expands = []
        if (row) {
          that.expands.push(row.id)
        }
      } else {
        that.expands = []
      }
    },
    handleCellClick (row, column, cell, event) {
      this.$emit('onHandleCellClick', row, column)

    },
  }
}
</script>

<style lang="scss" scoped>
.demo-table-expand {
  font-size: 0;
}
/deep/ .gutter {
  display: inline !important;
}
.el-table thead th {
  background-color: #f9f9f9;
}
.demo-table-expand label {
  width: 90px !important;
  color: #99a9bf !important;
}
.demo-table-expand .el-form-item {
  margin-right: 0 !important;
  margin-bottom: 0 !important;
  width: 50%;
}

.el-table--scrollable-x .el-table__body-wrapper::-webkit-scrollbar {
  overflow-x: hidden;
}

.el-table .el-table__body-wrapper::-webkit-scrollbar-thumb {
  background-color: rgba(169, 178, 196, 0.3) !important;
}

.el-table__fixed-right {
  height: calc(100% - 27px) !important;
}

.el_tab_alage {
  border: 1px solid #f0f0f0 !important;
  border-bottom: none !important;
  margin: {
    bottom: 20px !important;
    top: 20px !important;
  }
  .theHtml {
    width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .el-table__row {
    .cell {
      -webkit-line-clamp: 3 !important;
      -webkit-box-orient: vertical !important;
    }
    .el-button {
      margin: {
        top: 0 !important;
        right: 5px !important;
        bottom: 0 !important;
        left: 0 !important;
      }
    }
  }
}
</style>

2、使用组件

html 复制代码
<Table :table-label="tableHeader" v-loading="isSubmitLoading" :table-data="tableData" :table-option="tableOption" :table-selection="tableSelection" @onHandleSelectionChange="handleSelectionChange"></Table>
javascript 复制代码
import Pagination from "@/components/table/Pagination.vue";
export default {
	components: { Table },
	data() {
		return {
		 	isSubmitLoading: false,
			tableHeader:[],
			tableData: [],
			tableOption: {},
			tableSelection: {}
		}
	},
	methods: {
		handleSelectionChange() {},
		changeStatus() {}
	}
}

tableHeader中每个itemlabel(标题)、type(类型,分别有image图片,head头像,btn按钮,select下拉,switch开关,html自定义内容等)、list(对应列内容的字段名)、code: (row) => { return }(对列数据操作后返回函数)、overflowShow: 'hidden'(当内容过长被隐藏时显示 tooltip) 等。

如:

javascript 复制代码
tableHeader:[
	{
    label: "姓名", type: "html", list: 'name', overflowShow: 'hidden', code: (row) => {
      return row.type === 0 ? row.name : row.name + '(管理员)'
    }
  },{
  	label: "手机号", type: "html", overflowShow: 'hidden', code: (row) => {
      return row.phone === '' || row.phone === null ? '-' : row.phone
     }
  },{ 
 	label: "创建时间", list: 'createTime', overflowShow: 'hidden' 
  },{
     type: "switch",
     label: '状态',
     list: "state",
     offText: '禁用',
     onText: '启用',
     offValue: "1",
     onValue: "0",
     noSwitch: (row) => {
       return true;
     },
     method: (row) => {
       this.changeStatus(row)
     },
   },
]

tableOption中有label(标题)、width(对应列的宽度)、options(操作项,类型为数组,每个item中有label(标题)、color(颜色)、type(类型)、icon(图标)、method: (row) => {}(点击后执行的方法)、show:(row) => {}(显示或者隐藏的判断条件)

如:

javascript 复制代码
tableOpction: {
  label: '操作',
  width: '160px',
  options: [{
    label: '删除',
    color: '#DB864E',
    type: "text",
    icon: "",
    method: (row) => {
      this.doDelete(row.id);
    },
    show: (row) => {
      return row.type == 1 ? true : false
    }
  },
  {
    label: '编辑',
    color: '#DB864E',
    key: 1,
    type: "text",
    icon: "",
    method: (row) => {
      this.doEdit(row.id);
    },
  }
  ]
}

tableSelection配置中有key(为true时显示)、type(有index(显示索引)、selection(显示多选框)),操作多选框时会触发相应的handleSelectionChange回调函数,可以拿到已选中的数据。

javascript 复制代码
data() {
	return {
		tableSelection: {
	       key: true,
	       type: "selection"
	    }
	}
},
methods: {
	handleSelectionChange(val) {}
}

二、Pagination组件

1、封装Pagination组件为Pagination.vue文件如下:

html 复制代码
<template>
  <div class="pagination">
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="page.page"
      :page-sizes="pageSizes"
      :page-size="page.limit"
      layout="total, sizes, prev, pager, next, jumper" :total="total">
    </el-pagination>
  </div>
</template>

<script>
export default {
  props: {
    total: {
      type: Number,
      default: () => {}
    },
    pageSizes: {
      type: Array,
      default: () => {
        return [5, 10, 20, 100]
      }
    }
  },
  data() {
    return {
      page: {
        page: 1,
        limit: 20
      }
    }
  },

  methods: {
    Page(val) {
      this.page.page = val
    },
    handleSizeChange(val) {
      this.page.limit = val
      this.$emit('pageChange', this.page)
    },
    handleCurrentChange(val) {
      this.page.page = val
      this.$emit('pageChange', this.page)
    }
  }
}
</script>

<style scoped lang="scss">
  .pagination {
    float: right;
    padding: 1% 4% 2% 0px;
  }
</style>

2、使用组件

html 复制代码
<pagination ref="page" :total="total" @pageChange="pageChange"></pagination>
javascript 复制代码
import Pagination from "@/components/table/Pagination.vue";
export default {
	components: { Pagination },
	data() {
		return {
			total: 0,
			pageSize: 20,
			currentPage: 1
		}
	},
	methods: {
		pageChange (item) {
	      this.pageSize = item.limit;
	      this.currentPage = item.page;
	      this.fetchData(); // 请求数据
	    },
	}
}

total(总条目数)、pageChange(pageSize 改变时会触发)

相关推荐
别拿曾经看以后~11 分钟前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
我要洋人死14 分钟前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人26 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人26 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR32 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香34 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q24985969337 分钟前
前端预览word、excel、ppt
前端·word·excel
小华同学ai42 分钟前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍