对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 改变时会触发)

相关推荐
前端小小王12 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发22 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀44 分钟前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6413 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻4 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云4 小时前
npm淘宝镜像
前端·npm·node.js
dz88i84 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr4 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook