基于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 相关文章推荐
javascript oop开发滑动(slide)菜单控件
Aug 25 Javascript
查看图片(前进后退)功能实现js代码
Apr 24 Javascript
JavaScript的递归之递归与循环示例介绍
Aug 05 Javascript
js面向对象之静态方法和静态属性实例分析
Jan 10 Javascript
利用vue写todolist单页应用
Dec 15 Javascript
实现一个简单的vue无限加载指令方法
Jan 10 Javascript
字太多用...代替的方法(两种)
Mar 15 Javascript
webpack4的迁移的使用方法
May 25 Javascript
JS原生带缩略图的图片切换效果
Oct 10 Javascript
微信小程序调用微信支付接口的实现方法
Apr 29 Javascript
Vue项目配置跨域访问和代理proxy设置方式
Sep 08 Javascript
vue图片裁剪插件vue-cropper使用方法详解
Dec 16 Vue.js
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
fleaphp常用方法分页之Pager使用方法
2011/04/23 PHP
解析php中mysql_connect与mysql_pconncet的区别详解
2013/05/15 PHP
PHP中如何实现常用邮箱的基本判断
2014/01/07 PHP
本地计算机无法启动Apache故障处理
2014/08/08 PHP
PHP利用MySQL保存session的实现思路及示例代码
2014/09/09 PHP
Laravel5.7 数据库操作迁移的实现方法
2019/04/12 PHP
ThinkPhP+Apache+PHPstorm整合框架流程图解
2020/11/23 PHP
js控制容器隐藏出现防止样式变化的两种方法
2014/04/25 Javascript
基于html5和nodejs相结合实现websocket即使通讯
2015/11/19 NodeJs
Bootstrap开发实战之第一次接触Bootstrap
2016/06/02 Javascript
angular分页指令操作
2017/01/09 Javascript
基于jQuery实现数字滚动效果
2017/01/16 Javascript
Bootstrap模态窗口源码解析
2017/02/08 Javascript
JavaScript实现简单图片轮播效果
2017/08/21 Javascript
浅谈vue的几种绑定变量的值 防止其改变的方法
2018/03/01 Javascript
在 Typescript 中使用可被复用的 Vue Mixin功能
2018/04/17 Javascript
vue中v-for循环给标签属性赋值的方法
2018/10/18 Javascript
详解在Vue.js编写更好的v-for循环的6种技巧
2020/04/14 Javascript
Python Socket编程入门教程
2014/07/11 Python
一些Python中的二维数组的操作方法
2015/05/02 Python
python+requests+unittest API接口测试实例(详解)
2017/06/10 Python
wxpython绘制圆角窗体
2019/11/18 Python
浅析python中while循环和for循环
2019/11/19 Python
Python运行DLL文件的方法
2020/01/17 Python
Django接收照片储存文件的实例代码
2020/03/07 Python
Matplotlib animation模块实现动态图
2021/02/25 Python
阿根廷在线宠物商店:Puppis
2018/03/23 全球购物
戛纳奢侈品商店:Jacques Loup法国
2019/11/04 全球购物
JPA的优势都有哪些
2013/07/04 面试题
优秀求职自荐信怎样写
2013/12/18 职场文书
爱与责任演讲稿
2014/05/20 职场文书
求职信怎么写范文
2014/05/26 职场文书
写字楼租赁意向书
2014/07/30 职场文书
2015年秋季运动会加油稿
2015/07/22 职场文书
六年级语文教学反思
2016/03/03 职场文书
Windows Server 2012 R2 磁盘分区教程
2022/04/29 Servers