基于Element封装一个表格组件tableList的使用方法


Posted in Javascript onJune 29, 2020

我们项目中使用的表格一般都比较类似,如果不进行封装的话,那么每个页面都可能有一些类似的代码。不仅浪费时间,而且由于开发人员不同的开发习惯。后期维护人员需要花费一点时间去看每个人的代码。所以我直接将表格做一个二次封装,只要一个人去维护这份代码即可。下面是我封装的内容

内容:

1、支持直接传入后台请求地址渲染列表,且参数修改之后自动刷新
2、支持自定义每一列的显示
3、支持根据内容自动撑开列宽
4、支持动态筛选表头
5、支持分页
6、防抖
7、列权限
...
更多请自行尝试

以下是tableList 组件的代码

<template>
<!--刷新按钮 和 筛选列的多选框 layout中要有 control 才显示,默认显示-->
 <div class="table">
 <div class="table-control" v-if="layoutKey.control">
  <div class="table-control-title" @click="reload">
  <i class="el-icon-refresh"></i></div>
  <el-dropdown class="table-control-title">
  <span class="el-dropdown-link"><i class="el-icon-s-operation table-control-icon"></i></span>
  <el-dropdown-menu slot="dropdown" class="table-control-checkbox">
   <el-checkbox-group v-model="headItems" @change="changeChecked">
   <el-checkbox class="table-control-checkbox-item"
       v-for="(item,index) in allColumn"
       :label="item"
       :key="index">{{item}}
   </el-checkbox>
   </el-checkbox-group>
  </el-dropdown-menu>
  </el-dropdown>
 </div>
 <!--列表主体-->
 <el-table class="table" style="width: 100%"
    ref="tableList"
    :data="tableData"
    :defaultSort.async="defaultSort"
    v-bind="$attrs"
    v-on="$listeners"
    @selectionChange="selectionChange"
    @sort-change="sortChange">
  <ex-table-column v-if="layoutKey.expand" type="expand" fixed>
  <slot name="expand" :data="props" slot-scope="props"/>
  </ex-table-column>
  <ex-table-column v-if="layoutKey.checkBox" fixed type="selection" :width="62"
      :selectable="selectable"/>
  <ex-table-column v-if="layoutKey.index" type="index" label="序号" width="60"/>
  <ex-table-column v-for="(column,index) in activeColumn" :key="index"
      :prop="column.field"
      :column-key="column.field" :label="column.title" :fixed="column.fixed"
      :sortable="column.sort" :selectable="column.selectable"
      :show-overflow-tooltip="column.tooltip"
      :autoFit='true' :width="column.width"
      :fitByClass="autoWidth(column.width)"
      :minWidth="column.minWidth || defaultWidth">
  <slot :name="column.field" :data="scope.row" :field="column.field" :content="column.field"
    :index="index" slot-scope="scope">
   <div>{{$utils.nvl(scope.row[column.field],'--')}}</div>
  </slot>
  </ex-table-column>
 </el-table>
 <!--分页控件,layout中要有 control 才显示,默认显示-->
 <el-pagination background small class="table-pagination"
     :current-page.sync="page.pageNo"
     :page-sizes="page.list"
     :page-size="page.pageSize"
     :layout="page.layout" :total="page.total"
     @current-change="handleCurrentChange"
     @size-change="handleSizeChange" v-if="layoutKey.page"/>
 </div>
</template>

<script>
 import debounce from 'lodash/debounce';
 import ExTableColumn from './ExTableColumn';

 export default {
 components: { ExTableColumn },
 // 提供出来给其他组件调用,具体用法参考 vue 官方用法
 provide() {
  return {
  tableList: this,
  };
 },

 props: {
 // 默认的表格大小
  defaultWidth: {
  type: Number,
  required: false,
  default: 100,
  },
 // 显示的控件,目前就page,control 两个可选,可根据需求自行扩展
  layout: {
  default: 'page,control',
  },
 // 多选时 返回的key,默认id
  checkKey: {
  type: [Number, String],
  default: () => 'id',
  },
 // 请求参数,必填
  req: {
  type: Object,
  required: true,
  default: () => ({
   url: undefined,
   type: 'post',
   params: {
   query: {},
   },
   pageNo: 1,
   pageSize: 1,
  }),
  },
 // 默认排序,参考 elementUI table 用法
  defaultSort: {
  type: [String, Object],
  required: false,
  },
  // 列表显示的列
  // {
   title : 必填 String,  显示的列名
   field : 必填 String ,  列中的key
   width : 选填,String  列宽,单位像素,
   fixed : 选填,String  是否固定的列,可选 right, left
   sort : 选填,Boolean  是否可排序
   expend: 选填,Boolean  是否可展开,配置slot:expand 显示展开内容
   limit :  选填,Boolean  权限控制,false 则不显示
  }
  columns: {
  type: Array,
  required: true,
  default: () => [{ title: '操作', field: 'ctrl', width: '60', fixed: 'right' }],
  },

 // 这一行的 CheckBox 是否可以勾选,用法参考elementUI table用法
  selectable: {
  type: Function,
  default: () => true,
  },
  
  // 其他table参数,都会传给table
 },
 data() {
  return {
  layoutKey: {},

  page: {
   list: [5, 10, 20, 50, 100],
   total: null,
   pageSize: 10,
   pageNo: 1,
   layout: 'total,sizes,prev,pager,next,jumper',
  },

  tableData: [],
  sort: '',
  checkRows: [],
  checkKeys: [],

  headItems: [],
  allColumn: [],
  activeColumn: [],
  };
 },

 methods: {
  sortChange({ prop, order }) {
  this.sort = `${prop} ${order === 'descending' ? 'desc' : 'asc'}`;
  this.refresh();
  },

  selectionChange(selection) {
  this.checkRows = selection;
  this.checkKeys = [];
  selection.map((row) => {
   this.checkKeys.push(row[this.checkKey]);
   return true;
  });
  this.$emit('selectionChange', selection);
  },

  /** **************************method*********************************** */

  // 分页
  async handleCurrentChange(currentPage) {
  this.page.pageNo = currentPage;
  this.$emit('handleCurrentChange', currentPage);
  await this.initTable({ vm: this });
  },

  handleSizeChange(size) {
  this.page.pageSize = size;
  this.page.pageNo = 1;
  this.$emit('handleSizeChange', size);
  this.initTable({ vm: this });
  },

  /** *****************************动态渲染头部************************************* */
  // 取消选中菜单
  changeChecked() {
  this.changeColumn({ vm: this });
  },
  changeColumn: debounce(async ({ vm }) => {
  const that = vm;
  const keys = new Set(vm.headItems);
  const activeColumn = vm.columns.filter((item) => {
   if (keys.has(item.title)) {
   return true;
   }
   return false;
  });
  that.activeColumn = activeColumn;
  that.activeColumn.splice(1, 0);
  }, 200),

  /** *****************************刷新************************************* */
  // 刷新表格数据(使用现有参数)
  refresh(type) {
  if (type === 'delete' && this.page.pageNo > 1 && this.tableData.length === 1) {
   this.page.pageNo = this.page.pageNo - 1;
  }
  this.initTable({ vm: this });
  },

  // 重新加载数据(重置到第一页)
  reload() {
  if (this.page.pageNo !== 1) {
   this.page.pageNo = 1;
  }
  this.initTable({ vm: this });
  },

  initTable: debounce(async ({ vm }) => {
  const that = vm;
  that.tableData = [];
  const params = that._.assign({
   pageNo: that.page.pageNo,
   pageSize: that.page.pageSize,
   sortStr: that.sort
  }, that.req.params); // 右值覆盖左值,返回左值
  // 发起请求,根据实际项目中,接口来做
  const { data } = await window.axios[that.req.type || 'post'](that.req.url, params);
  if (data && that.$utils.Type.isArray(data.result)) {
   that.tableData = data.result;
   that.page.total = data.total * 1;
  }
  that.$nextTick(() => {
   that.$emit('loadDone', that.tableData, params);
  });
  }, 300),

  getCheckRows() {
  return this.checkRows;
  },

  getCheckKeys() {
  return this.checkKeys;
  },

  handleHead(columns) {
  const allColumn = [];
  columns.map((item) => {
   if (!item.limit) {
   allColumn.push(item.title);
   }
   return true;
  });
  this.headItems = allColumn;
  this.allColumn = allColumn;
  this.changeChecked();
  },

  handleLayout() {
  const layout = this.layout;
  if (!layout) return null;
  layout.split(',')
  .map(
   (item) => {
   const key = item.trim();
   this.layoutKey[key] = true;
   return true;
   },
  );
  return this.layoutKey;
  },

  autoWidth(width) {
  if (this.$utils.isEmpty(width)) {
   return 'cell';
  }
  return width;
  },

  init() {
  this.handleLayout();
  this.handleHead(this.columns);
  if (this.defaultSort) {
   const { prop, order } = this.defaultSort;
   this.sort = `${prop} ${order === 'descending' ? 'desc' : 'asc'}`;
  }
  this.initTable({ vm: this });
  }
  ,
 },
 async created() {
  this.init();
 },

 watch: {
  queryParams: {
  handler() {
   this.reload({ vm: this });
  },
  },
  columns: {
  handler() {
   this.handleHead(this.columns);
  },
  },
 },
 computed: {
  queryParams() {
  if (this.$utils.isNotEmpty(this.req.params)) {
   return this.req.params;
  }
  return {};
  },
 },
 };
</script>

<style lang="less" scoped>
 @import './style/index';
</style>

使用方法

<template>
 <div>
 <table-list
  :req="tableReq"
  ref="tableList"
  :stripe="true" // table 原来的参数也是支持使用的,方法也支持使用。
  :columns="[
     {title:'用户名',field:'name',sort:'true',fixed:true},
     {title:'英文名',field:'aliasName',sort:'true',fixed:true},
     {title:'年龄',field:'age', sort:true},
     {title:'职业',field:'job', sort:true},
     {title:'邮箱',field:'email'},
     {title:'出生日期',field:'birthday'},
     {title:'家庭住址',field:'address'},
     {title:'户籍',field:'domicile'},
     ]">
  <!--格式化时间列,所有的列都可以这么使用,slot 名为列field-->
  <template slot="birthday" slot-scope="{data}">
  <span>{{format(data.birthday)}}</span>
  </template>
 </table-list>
 </div>
</template>

<script>
 import TableList from './table/components/TableList';

 export default {
 name: 'HelloWorld',
 components: { TableList },
 data() {
  return {
  tableReq: {
   url: '/user/list', //必填
   type: 'post', //可选, 默认 post
   params: {} // 可选
  }
  };
 },

 methods: {
  format(time) {
  if (this.$utils.isEmpty(time)) return '/';
  return this.$utils.format(new Date(time), 'yyyy-MM-dd HH:mm');
  },
 },

 mounted() {
 }
 };
</script>

以下是显示效果

基于Element封装一个表格组件tableList的使用方法

到此这篇关于基于Element封装一个表格组件tableList的使用方法的文章就介绍到这了,更多相关Element tableList内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js判断浏览器的比较全的代码
Feb 13 Javascript
js实现页面打印功能实例代码(附去页眉页脚功能代码)
Dec 15 Javascript
JS 毫秒转时间示例代码
Sep 22 Javascript
javascript实现存储hmtl字符串示例
Apr 25 Javascript
JavaScript将一个数组插入到另一个数组的方法
Mar 19 Javascript
jQuery页面加载初始化的3种方法(推荐)
Jun 02 Javascript
JS常用字符串方法(推荐)
Jan 15 Javascript
AngularJS实现表格的增删改查(仅限前端)
Jul 04 Javascript
vue+vux实现移动端文件上传样式
Jul 28 Javascript
layer弹出层 iframe层去掉滚动条的实例代码
Aug 17 Javascript
VUE 配置vue-devtools调试工具及安装方法
Sep 30 Javascript
JavaScript高阶教程之“==”隐藏下的类型转换
Apr 11 Javascript
iview实现图片上传功能
Jun 29 #Javascript
vue+animation实现翻页动画
Jun 29 #Javascript
vue+element实现图片上传及裁剪功能
Jun 29 #Javascript
vue实现匀速轮播效果
Jun 29 #Javascript
vant实现购物车功能
Jun 29 #Javascript
js实现随机点名器精简版
Jun 29 #Javascript
Node.js中出现未捕获异常的处理方法
Jun 29 #Javascript
You might like
PHP学习笔记 IIS7下安装配置php环境
2012/10/29 PHP
PHP正则表达式 /i, /is, /s, /isU等介绍
2014/10/23 PHP
PHP中使用GD库绘制折线图 折线统计图的绘制方法
2015/11/09 PHP
PHP编译configure时常见错误的总结
2017/08/17 PHP
编写跨浏览器的javascript代码必备[js多浏览器兼容写法]
2008/10/29 Javascript
jQuery中DOM操作实例分析
2015/01/23 Javascript
基于javascript实现单选及多选的向右和向左移动实例
2015/07/25 Javascript
JavaScript判断对象是否为数组
2015/12/22 Javascript
js日期插件dateHelp获取本月、三个月、今年的日期
2016/03/07 Javascript
JQuery和PHP结合实现动态进度条上传显示
2016/11/23 Javascript
详解vue事件对象、冒泡、阻止默认行为
2017/03/20 Javascript
详解webpack自定义loader初探
2018/08/29 Javascript
Bootstrap Table 双击、单击行获取该行及全表内容
2018/08/31 Javascript
Vuejs开发环境搭建及热更新【推荐】
2018/09/07 Javascript
Vue递归组件+Vuex开发树形组件Tree--递归组件的简单实现
2019/04/01 Javascript
Javascript基于OOP实实现探测器功能代码实例
2020/08/26 Javascript
打印出python 当前全局变量和入口参数的所有属性
2009/07/01 Python
Python模拟用户登录验证
2017/09/11 Python
Python实现批量读取图片并存入mongodb数据库的方法示例
2018/04/02 Python
tensorflow实现图像的裁剪和填充方法
2018/07/27 Python
python判断数字是否是超级素数幂
2018/09/27 Python
Django 视图层(view)的使用
2018/11/09 Python
Python matplotlib学习笔记之坐标轴范围
2019/06/28 Python
Python对接六大主流数据库(只需三步)
2019/07/31 Python
python实现网站微信登录的示例代码
2019/09/18 Python
python实现ftp文件传输系统(案例分析)
2020/03/20 Python
法国珠宝店:CLEOR
2017/01/29 全球购物
简述网络文件系统NFS,并说明其作用
2016/10/19 面试题
求职简历中个人的自我评价
2013/12/01 职场文书
2015年汽车销售经理工作总结
2015/04/27 职场文书
入团介绍人意见范文
2015/06/04 职场文书
职工食堂管理制度
2015/08/06 职场文书
朋友聚会祝酒词
2015/08/10 职场文书
家访教师心得体会
2016/01/23 职场文书
如何用JS实现简单的数据监听
2021/05/06 Javascript
如何用PHP实现多线程编程
2021/05/26 PHP