简单封装el-table表格组件 支持 render 动态渲染

先上代码

// el-table 再封装
<template>
  <div
    class="x-table"
    :style="minTableHeight ? `height: calc(100% - ${minTableHeight}px)` : null"
  >
    <el-table
      v-bind="$attrs"
      v-on="$listeners"
      :data="tableData"
      :max-height="tableHeight"
      @selection-change="selectionChange"
      ref="xTable"
      :style="{ '--line': cellLineNumber }"
    >
      <!-- 多选列 -->
      <template v-if="tableConfig.selection" align="left">
        <el-table-column
          type="selection"
          :width="tableConfig.selectionWidth || 40"
          :fixed="tableConfig.selectionFixed || null"
        ></el-table-column>
      </template>
      <!-- 序号列 -->
      <template v-if="tableConfig.index">
        <el-table-column
          type="index"
          :width="tableConfig.indexWidth || 50"
          :label="tableConfig.indexLabel || '序号'"
          :fixed="tableConfig.indexFixed || null"
        ></el-table-column>
      </template>
      <!-- 循环列 -->
      <TableTemplate
        :tableColumConfig="item"
        :key="index"
        v-bind="$attrs"
        v-on="$listeners"
        v-for="(item, index) in tableColumnConfig"
      ></TableTemplate>
      <!-- 提供一个插槽  -->
      <slot></slot>
    </el-table>
  </div>
</template>

<script>
import TableTemplate from "./table-template.vue";
export default {
  name: "XTable",
  props: {
    tableData: {
      type: Array,
      default: () => [],
    },
    tableConfig: {
      type: Object,
      default: () => {},
    },
    tableColumnConfig: {
      type: Array,
      require: true,
      default: () => [],
    },
    minusPart: {
      type: Number,
      default: () => 0,
    },
    minTableHeight: {
      type: Number,
      default: () => 0,
    },
    cellLineNumber: {
      type: Number,
      default: () => 2,
    },
  },
  data() {
    return {
      tableHeight: 0,
    };
  },
  mounted() {
    this.getTableHeight();
    window.addEventListener("resize", this.getTableHeight);
  },
  beforeMount() {
    window.removeEventListener("resize", this.getTableHeight);
  },
  methods: {
    getTableHeight() {
      this.$nextTick(() => {
        this.tableHeight = window.innerHeight - this.minusPart;
      });
    },

    selectionChange(val) {
      this.$emit("selectionChange", val);
    },
  },
  components: { TableTemplate },
};
</script>

<style lang="scss">
.x-table {
  .cell {
    padding: 0 10px;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box; //作为弹性伸缩盒子模型显示。
    -webkit-box-orient: vertical; //设置伸缩盒子的子元素排列方式--从上到下垂直排列
    -webkit-line-clamp: var(--line); //显示的行
  }
  th {
    background: rgb(240, 242, 245);
  }
  .x-table-template {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-start;
    .x-table-input {
      input {
        text-align: center;
      }
    }
  }
  .el-link {
    font-size: 12px;
  }
}
</style>

TableTemplate 组件

// 为了实现多级表头而做的子组件的再封装
<template>
  <el-table-column
    :label="tableColumConfig.label || ''"
    :width="tableColumConfig.width || ''"
    :min-width="tableColumConfig.minWidth || ''"
    :prop="tableColumConfig.prop"
    :align="tableColumConfig.align || 'left'"
    :header-align="tableColumConfig.headerAlign || 'left'"
    :fixed="tableColumConfig.fixed || null"
    :sortable="tableColumConfig.sortable || false"
  >
    <template slot-scope="scope">
      <!-- 循环可能存在的template数组 -->
      <div
        class="x-table-template"
        v-if="
          tableColumConfig.template &&
          Array.isArray(tableColumConfig.template) &&
          !tableColumConfig.children
        "
        :style="tableColumConfig.alignStyle || ''"
      >
        <div
          v-for="(i, _index) in renderItem(
            tableColumConfig.template,
            scope.row
          )"
          :key="_index"
        >
          <!-- 按钮项 -->
          <template v-if="i.type === 'button'">
            <el-button
              :type="i.assemblyType || 'primary'"
              :disabled="
                i.disabled
                  ? i.disabled({
                      row: scope.row,
                      route: $route,
                      exData: exData,
                    })
                  : false
              "
              @click="
                emitFunc(i.method || 'defaultMethod', {
                  row: scope.row,
                  index: scope.$index,
                  additionalParams: i.addParams || '',
                })
              "
            >
              {{ i.text }}
            </el-button>
          </template>
          <!-- icon项 -->
          <template v-else-if="i.type === 'icon'">
            <el-link
              :type="i.assemblyType || 'primary'"
              :disabled="
                i.disabled
                  ? i.disabled({
                      row: scope.row,
                      route: $route,
                      exData: exData,
                    })
                  : false
              "
              @click="
                emitFunc(i.method || 'defaultMethod', {
                  row: scope.row,
                  index: scope.$index,
                  additionalParams: i.addParams || '',
                })
              "
            >
              <!-- icon的样式 具体看 https://element.eleme.cn/#/zh-CN/component/icon -->
              <i :class="i.iconClass"></i>
            </el-link>
          </template>
          <!-- input输入框 -->
          <template v-else-if="i.type === 'input'">
            <el-input
              class="x-table-input"
              v-model="scope.row[`${tableColumConfig.prop}`]"
              :type="i.assemblyType || 'text'"
              :placeholder="i.placeholder || '请输入'"
              :disabled="
                i.disabled
                  ? i.disabled({
                      row: scope.row,
                      route: $route,
                      exData: exData,
                    })
                  : false
              "
              @blur="
                emitFunc(i.method || 'defaultMethod', {
                  row: scope.row,
                  index: scope.$index,
                  additionalParams: i.addParams || '',
                })
              "
            ></el-input>
          </template>
          <!-- 文字方面的 -->
          <template v-else-if="i.type === 'link'">
            <el-link
              :type="i.assemblyType || 'primary'"
              :disabled="
                i.disabled
                  ? i.disabled({
                      row: scope.row,
                      route: $route,
                      exData: exData,
                    })
                  : false
              "
              @click="
                emitFunc(i.method || 'defaultMethod', {
                  row: scope.row,
                  index: scope.$index,
                  additionalParams: i.addParams || '',
                })
              "
            >
              {{ i.text }}
            </el-link>
          </template>
          <!-- 非超链接 -->
          <template v-else-if="i.type === 'span'">
            <span
              @click="
                emitFunc(i.method || 'defaultMethod', {
                  row: scope.row,
                  index: scope.$index,
                  additionalParams: i.addParams || '',
                })
              "
              :style="i.spanStyle ? i.spanStyle(scope.row) : ''"
            >
              {{ i.span(scope.row) }}
            </span>
          </template>
          <template v-else-if="i.type === 'render'">
            <XTableReder
              v-bind="$attrs"
              v-on="$listeners"
              :sc="scope"
              :row="scope.row"
              :render="i.render(scope.row, that)"
              :rederStyle="i.classStyle ? i.classStyle(scope.row) : ''"
              @sss="sss"
            ></XTableReder>
          </template>
          <template v-else-if="i.type === 'renderLink'">
            <el-link
              v-for="(_x, _xindex) in i.renderLink(scope.row)"
              :key="_xindex"
              @click="
                emitFunc(i.method || 'defaultMethod', {
                  row: scope.row,
                  index: scope.$index,
                  additionalParams: i.addParams || '',
                  linkIndex: _xindex,
                })
              "
              :disabled="
                i.disabled
                  ? i.disabled({
                      row: scope.row,
                      route: $route,
                      exData: exData,
                    })
                  : false
              "
              :type="i.assemblyType ? i.assemblyType() : 'primary'"
              :style="i.linkStyle"
            >
              {{ _x }}
            </el-link>
          </template>
          <!-- 自定义值 -->
          <el-link
            @click="
              emitFunc(i.method || 'defaultMethod', {
                row: scope.row,
                index: scope.$index,
                additionalParams: i.addParams || '',
              })
            "
            v-if="i.supplement"
            :type="i.suppleType ? i.suppleType(scope.row) : ' '"
            :disabled="
              i.disabled
                ? i.disabled({
                    row: scope.row,
                    route: $route,
                    exData: exData,
                  })
                : false
            "
            >{{ i.supplement(scope.row) }}
          </el-link>
        </div>
      </div>

      <template v-else>
        {{ scope.row[`${tableColumConfig.prop}`] }}
      </template>
    </template>
    <!-- 可能存在的子集 -->
    <template v-if="tableColumConfig.children">
      <xtable-template
        v-for="(i, __index) in tableColumConfig.children"
        :key="__index"
        :tableColumConfig="i"
        v-bind="$attrs"
        v-on="$listeners"
      ></xtable-template>
    </template>
  </el-table-column>
</template>

<script>
import XTableReder from "./xTableReder.vue";
export default {
  name: "xtable-template",
  props: {
    tableColumConfig: {
      type: Object,
      default: () => {},
    },
  },
  computed: {
    that() {
      return this;
    },
    exData() {
      return window.localStorage.getItem("exData") || "";
    },
    // 是否渲染模板内的template
    renderItem() {
      return function (templateList, row) {
        if (!Array.isArray(templateList)) {
          return [];
        }
        return templateList.filter((i) => {
          return i.showItem
            ? i.showItem({
                row: row,
                route: this.$route,
                exData: this.exData,
              })
            : true;
        });
      };
    },
  },
  methods: {
    emitFunc(method, row) {
      this.$emit(method, row);
    },
  },
  components: { XTableReder },
};
</script>

<style lang="scss" scoped></style>

//XTableReder 组件

<script>
export default {
  functional: true,
  props: {
    row: {
      type: Object,
      required: true,
    },
    render: {
      type: Function,
      required: true,
    },
    sc: {
      type: Object,
      required: true,
    },
    rederStyle: {
      type: String,
      require: true,
    },
  },
  render: (h, ctx) => {
    const arr = [];
    const params = {
      row: ctx.props.row,
      index: ctx.props.sc.$index,
    };
    const VNode = ctx.props.render(h, params);
    arr.push(VNode);
    return h("div", { class: ctx.props.rederStyle }, arr);
  },
};
</script>

使用方式

<template>
  <div>
     <XTable
      class="width:100%"
      :tableData="tableData"
      :tableConfig="{}"
      :minusPart="220"
      :minTableHeight="130"
      :tableColumnConfig="tableColumnConfig"
      @showDialog="showRelationDialog"
      @release="release"
      @deleteOne="showRelationDialog"
    ></XTable>
  </div>
</template>

<script>
import XTable from "@/components/xTable/index.vue";
export default {
  name: "RxdXuzyTestTest01",
  components: {
    XTable,
  },
  data() {
    return {
      tableData: [
        {
          a: 2,
          b: 2,
          c: 44,
        },
        {
          a: 1,
          b: 3,
          c: 45,
        },
      ],
      /**
       * label  number  列名
       * width  number  列宽
       * minWidth  number  最小列宽
       * prop   string  列绑定字段
       * align  string  列内排序方式  默认 left
       * headerAlign  string  列头排序方式 默认 left
       * fixed  string  列的定位布局
       * template  array  template绑定数组
       * -----template-----
       *    type  string  组件名 目前支持 btn input icon link
       *    assemblyType  string  组件样式 默认 primary
       *    disabled  boolean  是否禁用  默认 false
       *    placeholder  string  input输入框的提示句  默认  请输入
       *    method  string  除了input是blur触发外 其他都是点击触发  默认触发函数是 defaultMethod 请在父元素接收
       *    text string  link和button内显示的文字
       *    !注意  input默认绑定的是父级的prop
       *
       */
      tableColumnConfig: [
        {
    label: "模型名称",
    prop: "modelName",
  },
  {
    label: "更新时间",
    prop: "updateTime",
  },
  {
    label: "脚本编码",
    prop: "scriptCode",
  },
  {
    label: "关联采集",
    prop: "configId",
    template: [
      {
        supplement: (row) => {
          const str = row.configId || "";
          const strList = str.split(",");
          return strList.length;
        },
      },
    ],
  },
  {
    label: "模型描述",
    prop: "modelDesc",
  },
  {
    label: "审批状态",
    template: [
      {
        type: "span",
        span: (row) => statusOptions[row.status].label || "",
      },
    ],
  },

  {
    label: "操作",
    width: "165px",
    fixed: "right",
    headerAlign: "center",
    alignStyle: "justify-content: center;",
    template: [
      {
        type: "link",
        text: "详情",
        method: "showDialog",
        addParams: 1,
      },
      {
        type: "link",
        text: "编辑",
        method: "showDialog",
        addParams: 2,
        disabled: ({ row }) => row.status == 1,
      },
      {
        type: "link",
        text: "删除",
        method: "deleteOne",
        addParams: -1,
        disabled: ({ row }) => row.status == 1,
      },
      // {
      //   type: "link",
      //   text: "发布",
      //   method: "release",
      //   disabled: ({ row }) => row.status != 0,
      //   showItem: () => {
      //     const roleArr =
      //       JSON.parse(window.localStorage.getItem("roleArr")) || [];
      //     return roleArr.includes("model_manage");
      //   },
      // },
    ],
  },
  {
    label: "动态渲染",
    template: [
      {
        type: "render",
        render: (row, vue) => {
          function onClick() {
            vue.$emit("sss");
          }

          return function (h, ctx) {
            return <el-link onClick={onClick}>哈哈</el-link>;
          };
        },
        classStyle: (row) => "",
      },
    ],
  },
      ],
      tableConfig: {
        index: true, //是否需要index列
        indexWidth: 60, //index列宽
        indexLabel: "序号", //index列label
        indexFixed: "left", //index列是否开启fixed布局,如写则开启
        selection: true, //是否需要多选列
        selectionWidth: 60, //多选列宽
        selectionFixed: "left", //index列是否开启fixed布局,如写则开启
      },
    };
  },

  mounted() {},

  methods: {
    showSomeThing({ row = {}, index = 0 }) {
      console.log(row);
      console.log(index);
    },
  },
};
</script>

<style lang="scss" scoped></style>

配置相关

      tableConfig: {
        stripe: true, //是否开启斑马纹
        border: true, //是否开启边框
        index: true, //是否需要index列
        indexWidth: 60, //index列宽
        indexLabel: "序号", //index列label
        indexFixed: "left", //index列是否开启fixed布局,如写则开启
        selection: true, //是否需要多选列
        selectionWidth: 60, //多选列宽
        selection: "left", //index列是否开启fixed布局,如写则开启
      },
tableColumnConfig: [
        {
          label: "h",
          prop: "a",
          align: "center",
          headerAlign: "center",
        },
        {
          label: "s",
          prop: "b",
          template: [
            {
              type: "input",
              prop: "b",
              method: "showSomeThing",
            },
            {
              type: "button",
              text: "b",
              method: "showSomeThing",
            },
          ],
        },
      ],
// 接收自定义的子组件事件
    showSomeThing({ row = {}, index = 0 }) {
      console.log(row);
      console.log(index);
    },

tableColumnConfig 结构解析

  	   * label  number  列名
       * width  number  列宽
       * minWidth  number  最小列宽
       * prop   string  列绑定字段
       * align  string  列内排序方式  默认 left
       * headerAlign  string  列头排序方式 默认 left
       * fixed  string  列的定位布局
       * template  array  template绑定数组
       * -----template-----
       *    type  string  组件名 目前支持 btn input icon link
       *    assemblyType  string  组件样式 默认 primary 
       *    disabled  boolean  是否禁用  默认 false
       *    placeholder  string  input输入框的提示句  默认  请输入
       *    method  string  除了input是blur触发外 其他都是点击触发  默认触发函数是 defaultMethod 请在父元素接收
       *    text string  link和button内显示的文字
       *    !注意  input默认绑定的是父级的prop 
       *    

修改了一下绑定方式 ,可以直接在调用组件里使用 el-table 的api了同时支持了 render 渲染 这个组件的开发暂时告一段落了

gitee仓库地址

你可能感兴趣的:(js,javascript,vue.js,elementui)