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 相关文章推荐
js与jquery中获取当前鼠标的x、y坐标位置的代码
May 23 Javascript
JavaScript中判断原生函数检查function是否是原生代码
Sep 09 Javascript
Jquery 1.9.1源码分析系列(十二)之筛选操作
Dec 02 Javascript
浅析jQuery Mobile的初始化事件
Dec 03 Javascript
JS判断字符串变量是否含有某个字串的实现方法
Jun 03 Javascript
真正好用的js验证上传文件大小的简单方法
Oct 27 Javascript
require、backbone等重构手机图片查看器
Nov 17 Javascript
JSON键值对序列化和反序列化解析
Jan 24 Javascript
Bootstrap实现翻页效果
Nov 27 Javascript
vue2.0实现前端星星评分功能组件实例代码
Feb 12 Javascript
使用use注册Vue全局组件和全局指令的方法
Mar 08 Javascript
layer页面跳转,获取html子节点元素的值方法
Sep 27 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+MySql实现学生信息管理系统实例
2020/08/04 PHP
js数组转json并在后台对其解析具体实现
2013/11/20 Javascript
jQuery实现鼠标划过修改样式的方法
2015/04/14 Javascript
javascript实现控制div颜色
2015/07/07 Javascript
浅谈jQuery的offset()方法及示例分享
2015/07/17 Javascript
JavaScript String 对象常用方法总结
2016/04/28 Javascript
Bootstrap编写一个同时适用于PC、平板、手机的登陆页面
2016/06/30 Javascript
浅谈angularJS中的事件
2016/07/12 Javascript
Js操作DOM元素及获取浏览器高宽的简单方法
2016/09/08 Javascript
JS中解决谷歌浏览器记住密码输入框颜色改变功能
2017/02/13 Javascript
jQuery返回定位插件详解
2017/05/15 jQuery
单行 JS 实现移动端金钱格式的输入规则
2017/05/22 Javascript
vue 组件高级用法实例详解
2018/04/11 Javascript
在create-react-app中使用css modules的示例代码
2018/07/31 Javascript
layui从数据库中获取复选框的值并默认选中方法
2018/08/15 Javascript
JavaScript数据结构与算法之检索算法示例【二分查找法、计算重复次数】
2019/02/22 Javascript
jQuery实现可编辑的表格
2019/12/11 jQuery
javascript如何使用函数random来实现课堂随机点名方法详解
2020/07/28 Javascript
[19:54]夜魇凡尔赛茶话会 第一期02:看图识人
2021/03/11 DOTA
Python 2.7.x 和 3.x 版本的重要区别小结
2014/11/28 Python
Python实现简单截取中文字符串的方法
2015/06/15 Python
python创建文件备份的脚本
2018/09/11 Python
python+selenium实现自动抢票功能实例代码
2018/11/23 Python
浅谈python中str字符串和unicode对象字符串的拼接问题
2018/12/04 Python
Python图像处理之图像的读取、显示与保存操作【测试可用】
2019/01/04 Python
Django 外键的使用方法详解
2019/07/19 Python
Python Selenium参数配置方法解析
2020/01/19 Python
利于python脚本编写可视化nmap和masscan的方法
2020/12/29 Python
基于DOM+CSS3实现OrgChart组织结构图插件
2016/03/02 HTML / CSS
通过css3的filter滤镜改变png图片的颜色的示例代码
2020/05/06 HTML / CSS
简述安装Slackware Linux系统的过程
2012/05/08 面试题
内业资料员岗位职责
2014/01/04 职场文书
青年文明号口号
2014/06/17 职场文书
承德避暑山庄导游词
2015/02/03 职场文书
如何将numpy二维数组中的np.nan值替换为指定的值
2021/05/14 Python
利用Python实现模拟登录知乎
2022/05/25 Python