vue项目中element-ui的表格table的二次封装

8 篇文章 0 订阅
5 篇文章 0 订阅

欢迎点击领取 -《前端开发面试题进阶秘籍》:前端登顶之巅-最全面的前端知识点梳理总结

*分享一个使用比较久的🪜
在这里插入图片描述

vue2.X element-ui table的二次封装

1. 简介

因小编之前主写react,已经习惯数据表格的json配置;而element-ui的table主要是以template的方式进行页面的渲染,容易造成业务代码可观性并不是很友好,维护也不是很方便;element-ui的成熟度、以及使用率很大,市场上面的大多封装也很多,可扩展性也很方便。这里小编也做了一套简易版的二次封装,希望能帮到各位。

2. 展现

组件名我称为TableList,一个可以快速生成查询列表的封装组件,因项目组的原因未能使用jsx+render的方式来进行组件式的开发,有兴趣的可以自己试试;为了使扩展性更强,下面将Search查询组件和Table组件进行了分离封装;写过react的大家都知道props的传参方式{…props}很方便,那么vue的怎么支持这样的一个方式,下面我就使用到了v-bind属性绑定方式

在这里插入图片描述

3. 实现方式及使用
/**
 * TableList表格组件
 */
/**
 * Table表格
 */
<template>
  <div class="table_list_fix">
    <!-- 扩展性内容 -->
    <slot name="content_context"></slot>

    <!-- table中间button eg:导出 -->
    <div v-if="extendButton && extendButton.length > 0" class="btn-operates">
      <a :key="index" :href="item.href || null" @click="item.method()" v-for="(item, index) in extendButton">
        <el-button size="small" type="primary">{{ item.title }}</el-button>
      </a>
    </div>

    <!-- table表格 -->
    <el-table
      size="small"
      v-bind="options"
      :border="border"
      :data="dataSource"
      v-loading="loading"
      v-on="tableEvents"
      ref="multipleTable"
      style="width: 100%;"
      :header-cell-style="{ background: '#F5F7FA' }"
      @selection-change="handleSelectionChange"
    >
      <!-- 复选框 -->
      <el-table-column
        type="selection"
        style="width: 55px;"
        v-if="options && options.selection && (!options.isShow || options.isShow())"
      />

      <el-table-column
        width="55"
        align="center"
        type="index"
        v-if="options && options.index"
        :label="options && options.labelIndex"
      />

      <!-- 表格数据 -->
      <template v-for="(column, index) in columns">
        <el-table-column
          :key="index"
          v-bind="column.props"
          :prop="column.prop"
          :label="column.label"
          :align="column.align"
          :width="column.width"
          show-overflow-tooltip
          v-if="!column.isShow || (column.isShow && column.isShow())"
        >
          <template slot-scope="scope">
            <template v-if="!column.render">
              <template v-if="column.formatter">
                <span
                  v-html="column.formatter(scope.row, column, scope.$index)"
                  @click="column.click && column.click(scope.row, scope.$index)"
                ></span>
              </template>
              
              <!-- 跳转操作 -->
              <template v-else-if="column.newjump">
                <router-link
                  class="newjump"
                  v-bind="{ target: '_blank', ...column.target }"
                  :to="column.newjump(scope.row, column, scope.$index)"
                  >{{ scope.row[column.prop] || column.content }}</router-link
                >
              </template>
              
			  <!-- slot插槽 -->
              <template v-else-if="column.slot">
                <slot :slotName="column.slot" :row="scope.row" :index="index" />
              </template>
			
			  <!-- 操作按钮 -->
              <template v-else-if="column.children">
                <template v-for="(btn, key) in column.children">
                  <span :key="key" v-if="!btn.isShow || (btn.isShow && btn.isShow(scope.row, scope.$index))">
                    <el-button
                      :icon="btn.icon"
                      :plain="btn.plain"
                      style="padding: 6px"
                      :loading="scope.row?.loading"
                      :size="btn.size || 'small'"
                      :type="btn.type || 'text'"
                      :type="btn.type ? btn.type : 'primary'"
                      :disabled="btn.disabled && btn.disabled(scope.row, scope.$index)"
                      @click="btn.method(scope.row, scope.$index)"
                      >{{ btn.label }}</el-button
                    >
                  </span>
                </template>
              </template>

              <template v-else>
                <span
                  :style="column.click ? 'color: #409EFF; cursor: pointer;' : null"
                  @click="column.click && column.click(scope.row, scope.$index)"
                >
                  {{ scope.row[column.prop] || column.content }}
                  {{ `${scope.row[column.prop] && column.unit ? column.unit : ''}` }}
                </span>
              </template>
              
            </template>
            
            <template v-else>
              <render :column="column" :row="scope.row" :render="column.render" :index="index"></render>
            </template>
            
          </template>
        </el-table-column>
      </template>
    </el-table>
    <br />
    <!-- 分页部分 -->
    <el-pagination
      background
      v-if="pagination"
      :total="dataTotal"
      @size-change="handleSizeChange"
      :page-sizes="[5, 10, 20, 30, 50, 100]"
      :current-page="pagination.currentPage"
      :page-size="pagination.pageSize"
      @current-change="handleChangePage"
      :class="options && options.pageExtendLayout ? '' : 'pagination'"
      :layout="options && options.pageExtendLayout || 'total, prev, pager, next'"
    />
  </div>
</template>

<script>
const methods = {
  // 复选框选中项
  handleSelectionChange(val) {
    this.multipleSelection = val;
    this.$emit('handleSelectionChange', Array.from(val));
  },

  // 改变分页触发事件
  handleChangePage(val) {
    this.$emit('current-change', val);
  },

  handleSizeChange(page) {
    this.$emit('size-change', page);
  }
};

export default {
  name: 'TableList',
  props: {
    dataSource: {
      type: Array,
      default: () => []
    },
    columns: {
      type: Array,
      default: () => []
    },
    border: {
      type: Boolean,
      default: () => false
    },
    loading: {
      type: Boolean,
      default: () => false
    },
    slotcontent: {
      type: Boolean,
      default: () => false
    },
    dataTotal: {
      type: Number,
      default: 0
    },
    operates: Array,
    pagination: Object,
    extendButton: Array,
    options: Object,
    tableEvents: Object
  },

  data() {
    return {
      multipleSelection: []
    };
  },

  methods,

  mounted() {
    this.$nextTick(() => {
      this.$emit('toggleRowSelection', this.$refs.multipleTable);
    });
  },

  components: {
    render: {
      functional: true,
      props: {
        row: Object,
        render: Function,
        index: Number,
        column: {
          type: Object,
          default: null
        }
      },
      render: (h, opt) => {
        const params = {
          row: opt.props.row,
          index: opt.props.index
        };
        if (opt.props.column) params.column = opt.props.column;
        return opt.props.render(h, params);
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.table_list_fix {
  overflow: hidden;
  .btn-operates {
    margin-bottom: 6px;
    a {
      color: #fff;
      text-decoration: none;
      display: inline-block;
    }
  }
}
.table-header {
  padding-top: 10px;
  .table-header_button {
    text-align: right;
    float: right;
    margin-bottom: 12px;
    line-height: 40px;
  }
}
.newjump {
  text-decoration: none;
  color: dodgerblue;
}
.pagination {
  text-align: end;
  padding-bottom: 15px;
}
</style>
/**
 * 查询条件组件
 */
<template>
  <div class="formSearch">
    <div class="table-header" v-if="tableSearch && tableSearch.length > 0">
      <el-form
        size="small"
        :rules="rules"
        :model="formSearch"
        :inline="true"
        ref="formSearch"
        label-position="right"
        v-bind="{'label-width': '110px', ...(options && options.formProps)}"
      >
        <el-form-item
          class="table-header-item"
          :label="item.label + ':'"
          :prop="item.value"
          :key="index"
          v-bind="item.labelProps"
          v-for="(item, index) in tableSearch"
        >
          <el-select
            clearable
            v-bind="item.props"
            v-if="item.type === 'select'"
            v-model="formSearch[item.value]"
            :placeholder="`请选择${item.placeholder || item.label}`"
          >
            <el-option
              v-for="option in item.children"
              :key="option.value"
              :value="option.value"
              :label="option.label"
            />
          </el-select>
          <el-date-picker
            clearable
            style="width: 100%;"
            placeholder="选择日期"
            v-bind="item.props || {type: 'date'}"
            v-else-if="item.type === 'picker'"
            v-model="formSearch[item.value]"
          />
          <el-input
            v-else
            clearable
            v-bind="item.props"
            :type="item.inputType || 'text'"
            v-model="formSearch[item.value]"
            :placeholder="`请输入${item.placeholder || item.label}`"
            :maxlength="item.maxlength"
            @keyup.enter.native="handleSearch"
            :oninput="handleChangeInput(item)"
          />
        </el-form-item>
        <el-form-item>
          <el-button size="small" type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
          <el-button
            plain
            size="small"
            icon="el-icon-refresh-right"
            @click="handleReset('formSearch')"
          >重置</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import { convertParams } from "@/util/utilTool";

let methods = {
  // 搜索查询按钮
  handleSearch() {
    if (this.rules) {
      return this.$refs["formSearch"].validate(valid => {
        if (!valid) return false;
        this.$emit(
          "handleSearch",
          convertParams(Object.assign({}, this.formSearch))
        );
      });
    }
    this.$emit(
      "handleSearch",
      convertParams(Object.assign({}, this.formSearch))
    );
  },

  // 搜索重置按钮
  handleReset(formName) {
    this.$refs[formName].resetFields();
    this.formSearch = this.reset ? { ...this.value } : {};
    this.$emit("handleReset");
    if (this.reset) return false;
    this.handleSearch();
  },

  // input为number校验
  handleChangeInput(item) {
    return item.inputType === "number"
      ? this.handleOnInput(
          this.formSearch[item.value],
          item.value,
          item.rulesLength,
          item.maxlength
        )
      : null;
  },

  // input渲染长度校验
  handleOnInput(val, label, rulesLength, maxlength) {
    if (val && Number(val) <= 0) {
      this.formSearch[label] = 0;
    }
    if (rulesLength && val && val.length > maxlength) {
      this.formSearch[label] = this.formSearch[label].slice(0, maxlength);
    }
  }
};

export default {
  name: "FormSearch",
  props: {
    tableSearch: {
      type: Array
    },
    rules: {
      type: Object
    },
    value: {
      type: Object
    },
    reset: {
      type: Boolean
    },
    rulesLength: {
      type: Boolean
    },
    options: Object,
  },

  data() {
    return {
      formSearch: {
        ...this.value
      }
    };
  },

  methods,

  watch: {
    value(val) {
      if (val) return (this.formSearch = { ...this.value });
    }
  }
};
</script>

<style lang="less" scoped>
.table-header {
  padding-top: 10px;
  .table-header-item .el-form-item {
    width: 100%;
    display: flex;
    margin-bottom: 12px;
    .el-form-item__content,
    .el-select {
      width: 100%;
    }
  }
}
</style>
4. TableList使用文档

https://github.com/njt1340953658/TableList

简单的一个思路就是将繁琐的事情,通过json的数据结构模式,来帮助我们渲染ui层,将一部分的逻辑代码放在我们的组件内部,从而减少业务层代码的复杂性操作。

5. 思考
  • 如何在工作中达到快速开发,不在做重复性工作?
  • 怎样去思考自己的业务线去发展,沉淀出属于自己的东西
  • 如何去封装组件,怎么样才能够到达可观性、复用性,降低团队的开发成本
  • 身在职位长期的一个积累与思考、认知度要逐步去提高
  • 一定要学会去看api使用文档,在框架的时代也要逐步去习读源码。
6. 结语

小编也是前端小白,代码也有不合理之处,只是在闲余时间内简单写写,提升提升能力。以上代码可根据自己的项目去做调整。

  • 7
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Vue基于Element UI Table二次封装可以通过创建一个自定义的组件来实现。以下是一个简单的示例,演示了如何封装一个基于Element UI Table组件: ```vue <template> <el-table :data="tableData" :row-key="rowKey" :height="height"> <!-- 渲染表头 --> <el-table-column v-for="column in columns" :key="column.prop" :prop="column.prop" :label="column.label"> <!-- 自定义插槽 --> <template slot-scope="scope"> <slot :column="column" :scope="scope"></slot> </template> </el-table-column> </el-table> </template> <script> export default { name: 'CustomTable', props: { tableData: { type: Array, required: true }, columns: { type: Array, required: true }, rowKey: { type: String, required: true }, height: { type: String, default: 'auto' } } } </script> ``` 在这个示例,我们创建了一个名为`CustomTable`的组件。它接受`tableData`、`columns`、`rowKey`和`height`作为props,分别表示表格数据、表格列配置、行数据的唯一标识以及表格的高度。 在模板,我们使用`el-table`和`el-table-column`来渲染Element UI表格。我们使用了`v-for`指令来循环渲染表格列,并通过`slot-scope`来传递数据给插槽。插槽可以在父组件定义,并在插槽使用自定义的组件来渲染表格单元格内容。 通过这种方式,我们可以在父组件使用这个封装的自定义表格组件,并通过插槽来定制表格的内容和样式。 希望这个简单的示例能帮助到你进行Vue基于Element UI Table二次封装。如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SunnyRun!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值