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基础知识大集锦(一) 推荐收藏
Jan 13 Javascript
js 静态动态成员 and 信息的封装和隐藏
May 29 Javascript
js字符串转换成xml对象并使用技巧解读
Apr 18 Javascript
js获取当前页面路径示例讲解
Jan 08 Javascript
自己使用jquery写的一个无缝滚动的插件
Apr 30 Javascript
Javascript常用字符串判断函数代码分享
Dec 08 Javascript
JS实现向表格行添加新单元格的方法
Mar 30 Javascript
js仿百度切换皮肤功能(html+css)
Jul 10 Javascript
AngularJS实现数据列表的增加、删除和上移下移等功能实例
Sep 05 Javascript
vue按需引入element Transfer 穿梭框
Sep 30 Javascript
vue中mint-ui的使用方法
Apr 04 Javascript
JavaScript使用享元模式实现文件上传优化操作示例
Aug 07 Javascript
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接收POST数据方式
2015/06/05 PHP
详解php中curl返回false的解决办法
2019/03/18 PHP
基于jquery循环map功能的代码
2011/02/26 Javascript
利用js动态添加删除table行的示例代码
2013/12/16 Javascript
js简单实现交换Li的值
2014/05/22 Javascript
js正则表达式中exec用法实例
2015/07/23 Javascript
关于JS变量和作用域详解
2016/07/28 Javascript
javascript DOM的详解及实例代码
2017/03/06 Javascript
详解vue前后台数据交互vue-resource文档
2017/07/19 Javascript
Node.js dgram模块实现UDP通信示例代码
2017/09/26 Javascript
Vue.js 实现微信公众号菜单编辑器功能(一)
2018/05/08 Javascript
浅谈React的最大亮点之虚拟DOM
2018/05/29 Javascript
小程序封装wx.request请求并创建接口管理文件的实现
2019/04/29 Javascript
详解Vue3中对VDOM的改进
2020/04/23 Javascript
[46:09]2014 DOTA2华西杯精英邀请赛 5 25 LGD VS VG第三场
2014/05/26 DOTA
Python中的生成器和yield详细介绍
2015/01/09 Python
Python实现约瑟夫环问题的方法
2016/05/03 Python
django连接mysql配置方法总结(推荐)
2018/08/18 Python
Python3标准库总结
2019/02/19 Python
Python Django Cookie 简单用法解析
2019/08/13 Python
Python对接 xray 和微信实现自动告警
2019/09/17 Python
Django框架model模型对象验证实现方法分析
2019/10/02 Python
Python Print实现在输出中插入变量的例子
2019/12/25 Python
CSS3制作气泡对话框的实例教程
2016/05/10 HTML / CSS
去加拿大的旅行和假期:Canadian Affair
2016/10/25 全球购物
材料成型专业个人求职信范文
2013/09/25 职场文书
会计实习生工作总结的自我评价
2013/10/07 职场文书
董事长岗位职责
2013/11/30 职场文书
骨干教师考核评语
2014/12/31 职场文书
民政工作个人总结
2015/02/28 职场文书
大学生自荐书范文
2015/03/05 职场文书
保送生自荐信
2015/03/06 职场文书
2015年社区中秋节活动总结
2015/03/23 职场文书
2016元旦文艺汇演主持词
2015/07/06 职场文书
小学数学教师研修感悟
2015/11/18 职场文书
Python中常见的反爬机制及其破解方法总结
2021/06/10 Python