element-ui封装一个Table模板组件的示例


Posted in Javascript onJanuary 04, 2021

大家在做后台管理系统的时候,写的最多的可能就是表格页面了,一般分三部分:搜索功能区、表格内容区和分页器区。一般这些功能都是使用第三方组件库实现,比如说element-ui,或者vuetify。这两个组件库都各有各的优点,但就table组件来说,我还是比较喜欢vuetify的实现,不用手写一个个column,只要传入headers的配置数组就行,甚至分页器都内置在了table组件里,用起来十分方便。有兴趣可以看看:vuetify data table。

element-ui封装一个Table模板组件的示例

上面是一个经典的用element-ui开发的table页面,而且实际工作中如果每个table页面都写一遍,重复代码太多了,所以不妨写一个table模板组件,减少重复代码。我的思路是这样的:

搜索功能区:

提供searchBar插槽,可以自定义搜索输入框,搜索、重置按钮必有,新增按钮通过props控制显隐。这里对应的代码如下:

genSearchBar() {
  if (this.noSearchBar || !this.$scopedSlots.searchBar) return '';
  return (
    <el-form class="seatch-form" inline={true} label-width="100">
      {this.$scopedSlots.searchBar()}
      <el-button
        class="filter-item"
        icon="el-icon-search"
        type="primary"
        onClick={this.handleSearchBtnClick}
      >
        查询
      </el-button>
      <el-button
        class="filter-item"
        icon="el-icon-refresh"
        onClick={this.handleResetBtnClick}
      >
        重置
      </el-button>
      <el-button
        class="filter-item"
        icon="el-icon-plus"
        type="primary"
        v-show={this.showAddBtn}
        onClick={this.handleAddBtnClick}
      >
        新增
      </el-button>
    </el-form>
  );
}

表格内容区:

通过传入headers自动生成columns,参数如下:

{
  label: '性别',
  prop: 'sex',
  width: '180',
  filter: 'sexFilter'
}

可对应如下代码:

<el-table-column
         prop="sex"
         label="性别"
         width="180">
  <template slot-scope="scope">{{scope.row.sex | sexFilter}}</template>
</el-table-column>

注意,只支持全局filter。

如果你想自定义column,也提供tableColumn插槽,支持自定义column,可以如下配置:

{
  prop: 'action'
}
<el-table-column
         prop="action"
         label="操作"
         width="180">
  <template slot-scope="scope">
    <el-button>编辑</el-button>
    <el-button>删除</el-button>
  </template>
</el-table-column>

这样,就会按传入的prop匹配对应的column,十分方便。

实现代码如下:

genTableSlot(h) {
  let customeColumns = this.$scopedSlots.tableColumn
    ? this.$scopedSlots.tableColumn()
    : [];
  return this.headers.map((item) => {
    // 根据item.prop判断是否使用传入的插槽内容
    let foundItem = customeColumns.find(
      (ele) =>
        ele.componentOptions &&
        ele.componentOptions.propsData.prop === item.prop
    );
    return foundItem
      ? foundItem
      : h('el-table-column', {
         props: {
           ...item,
         },
         scopedSlots: {
           default: (props) => {
             // 根据传入的全局filter处理column数据
             let filter = this.$options.filters[
               item.filter
             ];
             let itemValue = props.row[item.prop];
             return h(
               'span',
               filter ? filter(itemValue) : itemValue
             );
           },
         },
       });
  });
}
genTable(h) {
  return h(
    'el-table',
    {
      ref: 'tableRef',
      props: {
        ...this.$attrs,
        data: this.data,
      },
      on: {
        'selection-change': (val) => {
          this.$emit('selection-change', val);
        },
      },
    },
    [...this.genTableSlot(h)]
  );
}

分页器区:

如无特殊需求,分页器功能一致,所以直接内置。

实现代码如下:

genPagination() {
  return (
    <div class="pagination-wrap">
      <el-pagination
        layout="total,prev,pager,next,jumper"
        current-page={this.current}
        page-size={this.pageSize}
        total={this.total}
        {...{
          on: { 'current-change': this.handleCurrentChange },
        }}
      ></el-pagination>
    </div>
  );
}

最后附完整代码和demo:

<script>
export default {
  name: 'TableTemplate',
  props: {
    data: {
      type: Array,
      default: () => [],
      required: true,
    },
    headers: {
      type: Array,
      default: () => [],
      required: true,
    },
    current: {
      type: Number,
      default: 1,
    },
    pageSize: {
      type: Number,
      default: 10,
    },
    total: {
      type: Number,
      default: 0,
    },
    noSearchBar: Boolean,
    showAddBtn: Boolean,
  },
  mounted() {
    this.$nextTick(() => {
      this.$emit('search');
    });
  },
  methods: {
    genSearchBar() {
      if (this.noSearchBar || !this.$scopedSlots.searchBar) return '';
      return (
        <el-form class="seatch-form" inline={true} label-width="100">
          {this.$scopedSlots.searchBar()}
          <el-button
            class="filter-item"
            icon="el-icon-search"
            type="primary"
            onClick={this.handleSearchBtnClick}
          >
            查询
          </el-button>
          <el-button
            class="filter-item"
            icon="el-icon-refresh"
            onClick={this.handleResetBtnClick}
          >
            重置
          </el-button>
          <el-button
            class="filter-item"
            icon="el-icon-plus"
            type="primary"
            v-show={this.showAddBtn}
            onClick={this.handleAddBtnClick}
          >
            新增
          </el-button>
        </el-form>
      );
    },
    genTableSlot(h) {
      let customeColumns = this.$scopedSlots.tableColumn
        ? this.$scopedSlots.tableColumn()
        : [];
      return this.headers.map((item) => {
        // 根据item.prop判断是否使用传入的插槽内容
        let foundItem = customeColumns.find(
          (ele) =>
            ele.componentOptions &&
            ele.componentOptions.propsData.prop === item.prop
        );
        return foundItem
          ? foundItem
          : h('el-table-column', {
             props: {
               ...item,
             },
             scopedSlots: {
               default: (props) => {
                 let filter = this.$options.filters[
                   item.filter
                 ];
                 let itemValue = props.row[item.prop];
                 return h(
                   'span',
                   filter ? filter(itemValue) : itemValue
                 );
               },
             },
           });
      });
    },
    genTable(h) {
      return h(
        'el-table',
        {
          ref: 'tableRef',
          props: {
            ...this.$attrs,
            data: this.data,
          },
          on: {
            'selection-change': (val) => {
              this.$emit('selection-change', val);
            },
          },
        },
        [...this.genTableSlot(h)]
      );
    },
    genPagination() {
      return (
        <div class="pagination-wrap">
          <el-pagination
            layout="total,prev,pager,next,jumper"
            current-page={this.current}
            page-size={this.pageSize}
            total={this.total}
            {...{
              on: { 'current-change': this.handleCurrentChange },
            }}
          ></el-pagination>
        </div>
      );
    },
    resetPagination() {
      this.$emit('update:current', 1);
    },
    handleCurrentChange(val) {
      this.$emit('update:current', val);
      this.$emit('search');
    },
    handleSearchBtnClick() {
      this.$emit('search');
    },
    handleResetBtnClick() {
      this.resetPagination();
      this.$emit('reset');
    },
    handleAddBtnClick() {
      this.$emit('add');
    },
    getTableRef() {
      return this.$refs.tableRef;
    },
  },
  render(h) {
    return (
      <div>
        {this.genSearchBar()}
        {this.genTable(h)}
        {this.genPagination()}
      </div>
    );
  },
};
</script>

<style scoped>
.seatch-form {
  text-align: left;
}
.pagination-wrap {
  margin-top: 20px;
  text-align: right;
}
</style>

Demo:

<template>
  <div>
    <table-template
      border
      :headers="headers"
      :data="tableData"
      :current.sync="current"
      :total="total"
      ref="tableTemplate"
      showAddBtn
      @search="handleSearch"
      @reset="handleReset"
      @add="handleAdd"
      @selection-change="handleSelectionChange"
    >
      <template #searchBar>
        <el-form-item label="姓名:" prop="title">
          <el-input class="filter-item" v-model="searchForm.title" ></el-input>
        </el-form-item>
      </template>
      <template #tableColumn>
        <el-table-column
          prop="selection"
          type="selection"
          width="55"
        ></el-table-column>
        <el-table-column prop="test" label="姓名" width="180">
          <template slot-scope="scope">
            <el-popover trigger="hover" placement="top">
              <p>姓名:{{ scope.row.name }}</p>
              <p>住址:{{ scope.row.address }}</p>
              <div slot="reference" class="name-wrapper">
                <el-tag size="medium">{{scope.row.name}}</el-tag>
              </div>
            </el-popover>
          </template>
        </el-table-column>
      </template>
    </table-template>
  </div>
</template>

<script>
import TableTemplate from './TableTemplate';
export default {
  name: 'Demo',
  components: {
    TableTemplate,
  },
  data() {
    return {
      current: 1,
      total: 100,
      headers: [
        {
          prop: 'selection',
        },
        {
          label: '姓名',
          prop: 'name',
          width: '100',
        },
        {
          label: '年龄',
          prop: 'year',
        },
        {
          label: '性别',
          prop: 'sex',
          width: 'sexFilter',
        },
        {
          prop: 'test',
        },
      ],
      tableData: [
        {
          name: 'curry',
          year: 18,
          sex: 'female',
          address: '天安门',
        },
      ],
      searchForm: {
        title: '',
      },
    };
  },
  methods: {
    handleSearch() {
      console.log(this.current);
    },
    handleReset() {
      this.searchForm = {
        title: '',
      };
    },
    handleAdd() {
      console.log('添加');
    },
    handleSelectionChange(val) {
      console.log(val);
    },
    getTableRef() {
      console.log(this.$refs.tableTemplate.getTableRef());
    },
  },
};
</script>

以上就是element-ui封装一个Table模板组件的示例的详细内容,更多关于element-ui封装组件的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
JavaScript具有类似Lambda表达式编程能力的代码(改进版)
Sep 14 Javascript
jQuery1.6 类型判断实现代码
Sep 01 Javascript
扩展Jquery插件处理mouseover时内部有子元素时发生样式闪烁
Dec 08 Javascript
jQuery 获取URL的GET参数值的小例子
Apr 18 Javascript
js使浏览器窗口最大化实现代码(适用于IE)
Aug 07 Javascript
jquery下拉select控件操作方法分享(jquery操作select)
Mar 25 Javascript
javascript每日必学之多态
Feb 23 Javascript
如何高效率去掉js数组中的重复项
Apr 12 Javascript
JS实现页面载入时随机显示图片效果
Sep 07 Javascript
在 Node.js 中使用 async 函数的方法
Nov 17 Javascript
vue-router为激活的路由设置样式操作
Jul 18 Javascript
vue+flask实现视频合成功能(拖拽上传)
Mar 04 Vue.js
ES2020让代码更优美的运算符 (?.) (??)
Jan 04 #Javascript
详解阿里Node.js技术文档之process模块学习指南
Jan 04 #Javascript
手写Vue源码之数据劫持示例详解
Jan 04 #Vue.js
js定时器出现第一次延迟的原因及解决方法
Jan 04 #Javascript
JavaScript实现页面高亮操作提示和蒙板
Jan 04 #Javascript
js正则表达式简单校验方法
Jan 03 #Javascript
vue+vant 上传图片需要注意的地方
Jan 03 #Vue.js
You might like
php批量删除数据
2007/01/18 PHP
strpos() 函数判断字符串中是否包含某字符串的方法
2019/01/16 PHP
基于PHP实现解密或加密Cloudflar邮箱保护
2020/06/24 PHP
JavaScript表单常用验证集合
2008/01/16 Javascript
读jQuery之六 缓存数据功能介绍
2011/06/21 Javascript
自己做的模拟模态对话框实现代码
2012/05/23 Javascript
Javascript setInterval的两种调用方法(实例讲解)
2013/11/29 Javascript
js命名空间写法示例
2015/12/18 Javascript
jQuery图片旋转插件jQueryRotate.js用法实例(附demo下载)
2016/01/21 Javascript
基于Javascript实现返回顶部按钮
2016/02/29 Javascript
jQuery实现为LI列表前3行设置样式的方法【2种方法】
2016/09/04 Javascript
原生js代码实现图片放大境效果
2016/10/30 Javascript
js实现微博发布小功能
2017/01/12 Javascript
ES6新特性之解构、参数、模块和记号用法示例
2017/04/01 Javascript
import与export在node.js中的使用详解
2017/09/28 Javascript
vue-router路由与页面间导航实例解析
2017/11/07 Javascript
从零开始搭建vue移动端项目到上线的步骤
2018/10/15 Javascript
手把手带你封装一个vue component第三方库
2019/02/14 Javascript
Python中os和shutil模块实用方法集锦
2014/05/13 Python
理解生产者消费者模型及在Python编程中的运用实例
2016/06/26 Python
深入理解NumPy简明教程---数组2
2016/12/17 Python
Python实现PS图像调整之对比度调整功能示例
2018/01/26 Python
python抓取文件夹的所有文件
2018/02/27 Python
Python 生成 -1~1 之间的随机数矩阵方法
2018/08/04 Python
TensorFlow实现iris数据集线性回归
2018/09/07 Python
使用Python脚本zabbix自定义key监控oracle连接状态
2019/08/28 Python
Python 中的pygame安装与配置教程详解
2020/02/10 Python
jupyter notebook 添加kernel permission denied的操作
2020/04/21 Python
pycharm使用技巧之自动调整代码格式总结
2020/11/04 Python
浅谈HTML5 defer和async的区别
2016/06/07 HTML / CSS
什么是唯一索引
2015/07/05 面试题
酒鬼酒广告词
2014/03/21 职场文书
商铺门面租房协议书
2014/10/21 职场文书
Jpa Specification如何实现and和or同时使用查询
2021/11/23 Java/Android
Python 读取千万级数据自动写入 MySQL 数据库
2022/06/28 Python
win11开机发生死循环重启怎么办?win11开机发生死循环重启解决方法
2022/08/05 数码科技