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

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

内容:

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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • element ui table(表格)实现点击一行展开功能

    前言 element ui是一个非常不错的vue的UI框架,element对table进行了封装,简化了vue对表格的渲染. element ui表格中有一个功能是展开行,在2.0版本官网例子中,只可以点击右箭头可以展开,我们的很多需求是点击某一行展开 那是不是无法实现呢?其实,借助element ui的一些属性,轻松实现点击某行展开,我们还是用2.0.9版本官网的例子, 对齐改造,使之可以做到这点 <template> <el-table :data="tableData5&

  • Element-UI Table组件上添加列拖拽效果实现方法

    Element-UI 的 Table组件很强大,但是我们的需求更强大... 简单粗暴的来一发效果图: 一.数据驱动 传统的拖动效果,都是基于通过 mousedown.mousemove.mouseup 事件来修改删减 dom 节点 但 Vue 是一个数据驱动的前端框架,开发时应尽量避免操作 dom 而且 Element-UI 的 Table 组件封装得很严谨,直接操作 dom 很容易产生不可预计的 bug 所以我的核心思路就是:通过一个数组渲染表头(列),然后修改这个数组的顺序,从而修改列表的列

  • Element-ui table中过滤条件变更表格内容的方法

    组件中: <el-table :data="users" highlight-current-row v-loading="listLoading" style="width: 100%;"> <el-table-column prop="sex" label="性别" width="100" :formatter="formatSex" sorta

  • elementUI中Table表格问题的解决方法

    前言 element ui是一个非常不错的vue的UI框架,element对table进行了封装,简化了vue对表格的渲染. 在开发vue框架项目时,引入element插件,使用table表格组件时,遇到了一些问题,以下列出以供参考. 1.表格样式问题: 混乱样式.png 正常样式.png 如上图,在当前导航表格table样式是没问题的,但当我点击别的导航去到另外的页面,然后再回到之前的导航页面,表格table的样式就会混乱,随便点击当前页面或刷新亦或拉伸页面,样式又恢复正常,很奇怪的样式问题.

  • VUE element-ui 写个复用Table组件的示例代码

    饿了么的table组件功能很强大,对于项目中的各种表格基本够用,但是--个人对于它以列为单位的操作不习惯 =.=所以改成了另一种方式(我不会告诉你其实本质没变). 项目中表格较多,所以复用性最重要 步骤一 先来个基本的表格展示 官例的tableData tableData: [{ date: '2016-05-02', name: '王小虎', address: '上海市普陀区金沙江路 1518 弄' }, { date: '2016-05-04', name: '王小虎', address:

  • VUE2.0 ElementUI2.0表格el-table自适应高度的实现方法

    在开发中,需要表格控件根据浏览器高度进行调整,固定表头,且然后多余的出滚动条,官方给出的: 只要在el-table元素中定义了height属性,即可实现固定表头的表格,而不需要额外的代码. 然后直接上template代码: <template> <el-table :data="tableData3" height="250" border style="width: 100%"> <el-table-column

  • element-ui 中的table的列隐藏问题解决

    element-ui 中的table和bootstrap中的table的某些设置还是有一定的差别的.之前用bootstrap做的表格,想要实现简短列和详细列的切换.因为详细列实在有太多列了,拉动滚动条还有一段距离.所以希望能够切换到简短列可以方便的看见比较重要的几列的内容.用之前的方法<bootstrap>的话,非常简单,直接设置display的显示和隐藏就可以了. 但是放在element-ui中来就不可行了.每一列根本不能直接设置样式,你给每一列设置class-name从而设置样式的话,可能

  • Element-UI中关于table表格的那些骚操作(小结)

    最近的项目中使用到element-ui组件库,由于做的是后台管理系统,所以经常需要操作表格,编辑样式的过程中遇到一些问题,官网针对table给出了很多的api,自己可以自定义,基本能满足产品需求,但是没有给出具体的案例,网上的资料也比较简略,这里简单整理下一些常用的操作,如果有类似的功能可以做一个参考. 具体的使用方法还是建议仔细阅读官网-table章节: https://element.eleme.cn/#/zh-CN/component/table#table-column-scoped-s

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

    我们项目中使用的表格一般都比较类似,如果不进行封装的话,那么每个页面都可能有一些类似的代码.不仅浪费时间,而且由于开发人员不同的开发习惯.后期维护人员需要花费一点时间去看每个人的代码.所以我直接将表格做一个二次封装,只要一个人去维护这份代码即可.下面是我封装的内容 内容: 1.支持直接传入后台请求地址渲染列表,且参数修改之后自动刷新 2.支持自定义每一列的显示 3.支持根据内容自动撑开列宽 4.支持动态筛选表头 5.支持分页 6.防抖 7.列权限 ... 更多请自行尝试 以下是tableList

  • 封装Vue Element的table表格组件的示例详解

    在封装Vue组件时,我依旧会交叉使用函数式组件的方式来实现.关于函数式组件,我们可以把它想像成组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的HTML(VNode).它比较适用于外层组件仅仅是对内层组件的一次逻辑封装,而渲染的模板结构变化扩展不多的情况,且它一定是无状态.无实例的,无状态就意味着它没有created.mounted.updated等Vue的生命周期函数,无实例就意味着它没有响应式数据data和this上下文. 我们先来一个简单的Vue函数式组件

  • 如何封装Vue Element的table表格组件

    在封装Vue组件时,我依旧会交叉使用函数式组件的方式来实现.关于函数式组件,我们可以把它想像成组件里的一个函数,入参是渲染上下文(render context),返回值是渲染好的HTML(VNode).它比较适用于外层组件仅仅是对内层组件的一次逻辑封装,而渲染的模板结构变化扩展不多的情况,且它一定是无状态.无实例的,无状态就意味着它没有created.mounted.updated等Vue的生命周期函数,无实例就意味着它没有响应式数据data和this上下文. 我们先来一个简单的Vue函数式组件

  • 你知道怎么基于 React 封装一个组件吗

    目录 antd 是如何封装组件的 仓库地址 divider 组件源代码 如何暴露组件属性 如何设置统一类名前缀 如何处理样式与类名 divider 组件样式源代码 总结 前言 很多小伙伴在第一次尝试封装组件时会和我一样碰到许多问题,比如人家的组件会有 color 属性,我们在使用组件时传入组件文档中说明的属性值如 primary ,那么这个组件的字体颜色会变为 primary 对应的颜色,这是如何做到的?还有别人封装的组件类名都有自己独特的前缀,这是如何处理的呢,难道是 css 类名全部加上前缀

  • 详解基于element的区间选择组件校验(交易金额)

    需求: 这里以项目的需求为例,基本的需求如下: 分为左右值,包含左右值,正整数 左侧必须大于等于1,右侧无限大,右侧值必须不小于左侧 左侧填写数据,右侧标为必填:右侧填写数据,左侧标为必填 失焦校验成果: 代码如下:(页面) <el-col :span="8" v-if="item.qttccType === 1"> <el-col :span="14"> <el-form-item :label="ite

  • 基于jQuery封装的分页组件

    由于项目需要实现分页效果,上jQuery插件库找了下,但是木有找到自己想要的效果,于是自己封装了个分页组件. 思路: 主要是初始化时基于原型建立的分页模板然后绑定动态事件并实现刷新DOM的分页效果. 1.page.init.css @charset "utf=8"; *{ box-sizing: border-box; padding: 0; margin: 0; } .page{ font-size: 13px; text-align: right; } .page .page_to

  • 一篇文章带你使用Typescript封装一个Vue组件(简单易懂)

    一.搭建项目以及初始化配置 vue create ts_vue_btn 这里使用了vue CLI3自定义选择的服务,我选择了ts.stylus等工具.然后创建完项目之后,进入项目.使用快捷命令code .进入Vs code编辑器(如果没有code .,需要将编辑器的bin文件目录地址放到环境变量的path中).然后,我进入编辑器之后,进入设置工作区,随便设置一个参数,这里比如推荐设置字号,点下.这里是为了生成.vscode文件夹,里面有个json文件. 我们在开发项目的时候,项目文件夹内的文件很

  • vue封装一个弹幕组件详解

    目录 前言 功能实现 1.获取随机颜色 随机数生成 随机颜色编码生成 2.随机生成弹幕出现的高度坐标 3.格式化弹幕对象 颜色 定位 4.创建弹幕对象 滚动动画定义 创建弹幕dom对象实例 弹幕销毁 弹幕循环 5.实时弹幕发送 html JavaScript 源码地址 前言 现在很多地方都有使用到弹幕,最近在捣鼓自己的个人博客网站,也想着在里面加入一个弹幕模块,所以在这里封装了一个可复用的弹幕组件,目前已经实现了基本的功能,可能还会有存在缺陷,后续会继续优化.这里给大家介绍分享一下实现的过程.

  • JavaScript基于inquirer封装一个控制台文件选择器

    目录 前言 插件效果 插件实现 Inquirer.js inquirer原有参数 二次封装 新增参数 代码实现 获取指定路径下的文件列表 获取指定路径下的目录列表 交互类型响应控制 选择文件 选择目录 基本类型调用Inquirer处理 插件使用 1.安装依赖 2.在代码中引用 3.示例代码 前言 我们在用脚手架初始化项目的时候,往往会进行一些命令交互,用过vue或者react的用脚手架新建项目的应该都进行过命令交互,vue创建的时候会让你选择vue2还是vue3,也有多选要什么配置,也有输入y或

  • 基于vue-upload-component封装一个图片上传组件的示例

    需求分析 业务要求,需要一个图片上传控件,需满足 多图上传 点击预览 图片前端压缩 支持初始化数据 相关功能及资源分析 基本功能 先到https://www.npmjs.com/search?q=vue+upload上搜索有关上传的控件,没有完全满足需求的组件,过滤后找到 vue-upload-component 组件,功能基本都有,自定义也比较灵活,就以以此进行二次开发. 预览 因为项目是基于 vant 做的,本身就提供了 ImagePreview 的预览组件,使用起来也简单,如果业务需求需要

随机推荐