element-ui table封装信息列表table-list,自动化处理(无需再写过多冗余的方法) - 戴向天

33 篇文章 0 订阅
14 篇文章 0 订阅

大家好!我叫戴向天

QQ群:602504799

如若有不理解的,可加QQ群进行咨询了解

<template>
  <div ref="table" :class="getClassName(full ? 'full' : '')">
    <el-table
      style="width:100%"
      :stripe="true"
      :class="getClassName('table')"
      :data="data"
      :border="border"
      :header-cell-class-name="center ? getClassName('center') : ''"
      :cell-style="{ 'text-align': 'left' }"
      cell-class-name="content-text"
      :header-cell-style="{
        background: 'rgba(245, 245, 247, 1)',
        color: '#49445f',
        'text-align': 'left',
      }"
      v-loading="pictLoading"
      element-loading-text="数据正在加载中"
      element-loading-spinner="el-icon-loading"
      @selection-change="selectionChange"
      :height="height || null"
    >
      <template slot="empty">
        <span>暂无数据</span>
      </template>
      <el-table-column type="selection" width="60" v-if="showSelection">
      </el-table-column>
      <el-table-column
        v-for="(item, key) in columns"
        :key="key"
        :label="item.label"
        :prop="item.prop"
        :width="item.width"
        :min-width="item.minWidth"
        :showOverflowTooltip="item.showOverflowTooltip"
      >
        <template slot-scope="scope">
          <div class="operation" v-if="item.is === 'operation'">
            <el-tooltip
              :content="button.name"
              v-for="(button, b) in scope.row.buttons"
              :key="b"
              placement="top"
            >
              <el-link
                :type="button.type"
                :class="getClassName('button')"
                size="small"
                @click="tableOperationHadnler(button.emit, scope.row)"
                >{{ button.name }}</el-link
              >
            </el-tooltip>
          </div>
          <div v-else>
            {{ scope.row[item.prop] }}
          </div>
        </template>
      </el-table-column>
    </el-table>
    <div v-if="showPagination" :class="getClassName('pagination')">
      <el-pagination
        background
        layout="total, sizes, prev, pager, next, jumper"
        :total="pagination.total"
        :page-size="pagination.size"
        :page-sizes="pagination.sizes"
        :current-page="pagination.currentPage"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
      ></el-pagination>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
@Component({
  name: 'TableList',
  components: {},
})
export default class TableList extends Vue {
  // 开启这个的话,将会实现实时请求,比如在关键词查询的时候,将会一边输入一边请求
  // @Watch("params", {
  //   deep: true,
  // })
  // private paramsWatch() {

  //   this.lastMethod = "";
  //   this.autoHandler();
  // }

  /**
   * 判读是否可以进行自动处理
   * 如果可以的话,将会返回请求的配置信息
   * 如果不可以的话,将会返回false
   */
  private get canHandler() {
    const dataType: string = typeof this.autoConfig;
    const all = dataType === 'function' ? this.autoConfig() : this.autoConfig;
    const { auto, method, rule, server } = all;

    // 是否具备自动处理的条件
    const conditional = 'auto' in all && 'method' in all;
    // 方法是不是字符串参数
    const isRightVoid = typeof method === 'string';
    // 是否进行自动处理
    const isAuto = typeof auto === 'boolean' && auto;
    // 是否有规则处理
    const hasRule = typeof rule === 'function';
    // 是否有服务
    const hasServer = typeof server === 'object';
    if (conditional && isRightVoid && isAuto && hasRule && hasServer) {
      return all;
    } else {
      return false;
    }
  }

  // 获取请求参数
  private get getParams() {
    const params = {
      ...(this.params || {}), // this.params只是作为一个辅助性的参数
    };
    const props = this.props; // 字段信息

    const pagination = this.pagination; // 分页信息

    // 字段信息转化
    return Object.keys(this.props).reduce((frist: any, str: string) => {
      const key = props[str];
      if (str === 'number') {
        // 页码数据
        frist[key] = pagination.currentPage;
      } else if (str === 'size') {
        frist[key] = pagination.size;
      }
      return frist;
    }, params);
  }
  @Prop({
    default: () => [],
  })
  private tableData?: any[];

  @Prop({
    default: true,
  })
  private full?: boolean;

  // 是否居中
  @Prop({
    default: false,
  })
  private center?: boolean;

  // 表格高度
  @Prop({
    default: false,
  })
  private border?: boolean;

  // 表格字段
  @Prop({
    default: () => [],
  })
  private columns?: any[];

  // 是否显示选择框
  @Prop({
    default: false,
  })
  private showSelection?: boolean;

  // 是否显示分页
  @Prop({
    default: true,
  })
  private showPagination?: boolean;

  // 是保存内容为一行,并且当鼠标移入的时候进行展示全文
  @Prop({
    default: true,
  })
  private showOverflowTooltip?: boolean;

  /**
   * Author: 戴向天
   * 自行处理的配置参数 - 主要是处理请求方面的事情
   * @param method {void} 请求函数 - 必传
   * @param params {Object} 请求参数  - 可选
   * @param auto {Boolean} 是否自行处理 - 必传
   * @param rule {void} 请求结果的处理规则 - 当请求到数据之后,将会以回调的形式调用 rule  - 必传
   *  rule 将会接收到一个请求的结果参数,
   *  rule 所需要做的处理就是将最终的结果进行返回出来
   * @param server {Vuex Server}
   * */
  @Prop({
    default: () => ({
      method: null,
      params: {},
      auto: false,
      rule: null,
      server: null,
    }),
  })
  private autoConfig?: any;

  /**
   *  请求的附属参数
   *  当前的tableList只是做关于分页的处理请求
   *  但是有些接口所需要的参数不仅仅是页码和页码数
   *  这个时候就可以通过params来进行告知tableList组件,在请求的时候还有一些附属性的参数
   * */
  @Prop({
    default: () => ({}),
  })
  private params?: any;

  /**
   * 分页的字段名称转化
   * 由于每个接口它的页码和页码数的字段名可能不是一致的,
   * 这个时候可以通过props来进行解决,目前的话,主要就是页码和页码数的字段可以进行更改
   *
   * {
   *    '//number': '取值就是接口所需要的页码字段名称'
   *    number: 'page', //页码
   *    '/size/': '取值就是接口所需要的页码数字段名称'
   *    size: 'pageSize' //页码数
   * }
   */
  @Prop({
    default: () => ({ number: 'number', size: 'size' }),
  })
  private props?: any;
  private height: string | number = '';

  // 分页参数
  private pagination: any = {
    size: 10,
    sizes: [10, 20, 30, 40, 50],
    total: 0,
    currentPage: 1,
  };

  // 自动处理的时候,将方法名进行保存下来
  private lastMethod: string = '';

  // 渲染数据
  private data: any = [];

  // 加载动画
  private pictLoading = false;

  // 已选中的数据
  private selections: any[] = [];

  @Watch('tableData', {
    deep: true,
  })
  private tableDataWatch() {
    this.data = JSON.parse(JSON.stringify(this.tableData || []));
  }

  // 表格按钮操作
  private tableOperationHadnler(emit: string, row: any) {
    this.$emit('tableOperationHadnler', emit, row);
  }

  // 表格选择
  private selectionChange(selections: any) {
    this.$emit('selectionChange', selections);
    this.selections = selections;
  }

  // 返回表格选中的数据
  private getSelections() {
    return this.selections;
  }

  private setPagination(data?: {
    size: number;
    sizes: number[];
    total: number;
    currentPage: number;
  }) {
    this.pagination = {
      ...this.pagination,
      ...data,
    };
  }

  // page size 有变化的时候进行触发
  private handleSizeChange(data: any) {
    this.pagination.size = data;
    this.autoHandler();
  }
  // 当前分页的页码有变化的时候进行触发
  private async handleCurrentChange(data: any) {
    this.pagination.currentPage = data;
    this.autoHandler();
  }

  // 请求处理
  private async requestHandler() {
    this.pictLoading = true;
    let params: any = this.getParams;
    if (
      this.canHandler.before &&
      typeof this.canHandler.before === 'function'
    ) {
      params = this.canHandler.before(params);
    }
    const res = await this.canHandler.server[this.canHandler.method](
      this.getParams,
    );
    const { total, data } = this.canHandler.rule(res);
    if (Array.isArray(data)) {
      if (
        data.length === 0 &&
        this.pagination.currentPage > 1 &&
        this.pagination.currentPage > 0
      ) {
        this.pagination.currentPage--;
        this.autoHandler();
      } else {
        this.data = data;
      }
    }
    this.pagination.total = total || 0;
    this.pictLoading = false;
  }

  /** 执行自动处理 */
  private autoHandler(reload?: boolean, num?: number) {
    if (this.canHandler) {
      if (this.lastMethod !== this.canHandler.method || reload) {
        this.lastMethod = this.canHandler.method;
        this.handleCurrentChange(num || 1);
      } else {
        // 为了防止数据未能及时更新,进行强行等待vue处理完成之后在进行执行
        this.$nextTick(this.requestHandler);
      }
    }
  }
  // 获取数据类型的方法
  private getType = (o: any, s?: string) => {
    let t = Object.prototype.toString.call(o).split(' ')[1];
    t = t
      .substring(0, t.length - 1)
      .trim()
      .toLowerCase();
    if (
      t === 'object' &&
      Object.prototype.toString.call(o).toLowerCase() === '[object object]' &&
      !o.length
    ) {
      t = 'json';
    }
    return s ? t === s : t;
  }

  private setHeight() {
    if (this.full) {
      const pH = (this.$el.querySelector('.el-table') as HTMLDivElement)
        .offsetHeight;
      const cH = ((this.$el.querySelector(
        '.el-table',
      ) as HTMLDivElement).querySelector(
        '.el-table__header-wrapper',
      ) as HTMLDivElement).offsetHeight;
      this.height = pH - cH;
    }
  }

  private mounted() {
    this.$nextTick(() => this.setHeight());
  }

  private created() {
    if (this.params[this.props.number]) {
      this.pagination.currentPage = this.params[this.props.number];
    }
    if (this.tableData) {
      this.data = JSON.parse(JSON.stringify(this.tableData || []));
    }
    this.autoHandler(true, this.pagination.currentPage);
  }
}
</script>

<style lang="less" scoped>
.tableList {
  &-full {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    padding: 0 0 unit(30 / @fontSize, rem);
    overflow: hidden;
    .tableList-table {
      flex-grow: 1;
    }
  }
  &-button {
    /deep/ span {
      font-size: unit(20 / @fontSize, rem);
    }
  }

  &-pagination {
    display: flex;
    margin-top: unit(10 / @fontSize, rem);
    justify-content: flex-end;
  }

  /deep/ .tableList-center > div {
    text-align: center;
  }
}
/deep/ .el-table thead {
  .el-checkbox {
    padding-left: unit(13 / @fontSize, rem);
  }
}
/deep/ table thead {
  .cell {
    font-size: unit(20 / @fontSize, rem);
    font-weight: bolder;
    color: #534d6a;
    padding: unit(5 / @fontSize, rem);
  }
}
.operation {
  /deep/ .el-link + .el-link {
    margin-left: unit(10 / @fontSize, rem);
  }
}
/deep/ .content-text {
  padding: unit(18 / @fontSize, rem) 0;
  /deep/.cell > div {
    font-size: unit(20 / @fontSize, rem);
  }
}
</style>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值