element-ui table 实现表格嵌套多层表格

项目需求:要求点击行中的“其他”单元格中的字段展开相应的子表

1.点击“扩展属性”出现"扩展属性"子表,点击“国家/地区”出现国家/地区子表

2.在国家/地区子表中还有个“生命周期字段”,点击“生命周期”出现“生命周期”的子表

 实现方案:使用table 中的type="expand" 同时把展开图标隐藏,给表格文字“扩展属性”、“国家/地区”添加点击事件,通过点击事件实现不同子表的切换

 当时做的时候是用v-if来实现对各级子表的显示和隐藏但是出现了问题就是,当点击顺序是 扩展属性-->国家/地区-->生命周期时会出现生命周期子表没有展示出来,如图:

当时使用$nextTick()/$forceUpdate()都没有用,把v-if换成v-show就没有问题了。看来频繁切换的显示和隐藏就要使用v-show

js代码:

 

 css:对type=expand属性的箭头展开样式隐藏

 同时要让width=1 的那一列的边框去掉

 这时当缩放浏览器时会出现表头错位的情况,需要再加一个样式

 下面是完整代码,搜索条件和表格字段有点多,大家可以忽略。若有不对的地方,欢迎指出,谢谢!

<template>
  <div>
    <el-form size="mini" :model="searchData" class="searchBox">
      <el-row :gutter="24">
        <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="4">
          <el-form-item label="skuId" class="textArea">
            <el-input
              v-model="searchData.skuIds"
              type="textarea"
              autosize
              placeholder="请输入"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="4">
          <el-form-item label="sku编码" class="textArea">
            <el-input
              v-model="searchData.skuCodes"
              type="textarea"
              autosize
              placeholder="请输入"
            ></el-input>
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="4">
          <el-form-item label="sku名称(中文)">
            <el-input v-model="searchData.skuNameCn" placeholder="请输入"></el-input>
          </el-form-item>
        </el-col>
        <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="4">
          <el-form-item label="Sku名称(英文)">
            <el-input v-model="searchData.skuNameEn" placeholder="请输入"></el-input>
          </el-form-item>
        </el-col>
        
        <el-col :xs="24" :sm="24" :md="12" :lg="6" :xl="4">
          <el-form-item>
            <el-button type="primary" @click="getTableData('init')">查询</el-button>
            <el-button @click="reset">重置</el-button>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <el-table
      v-loading="loading"
      row-key="skuId"
      size="mini"
      class="tableBox"
      :data="tableList"
      style="width:100%;"
      border
      :header-cell-style="{ background: '#fafafa' }"
      :expand-row-keys="expands"
    >
      <el-table-column type="expand" width="1">
        <template slot-scope="scopeOut">
          <el-table
            v-show="scopeOut.row.countryShow"
            ref="countryArea"
            :data="scopeOut.row.nations"
            border
            size="mini"
            row-key="id"
            :expand-row-keys="expandsInner"
            :header-cell-style="{ background: '#fafafa' }"
          >
            <el-table-column type="expand" width="1">
              <template slot-scope="scopeInner">
                <el-table
                  v-show="scopeInner.row.lifeShow"
                  :data="scopeInner.row.lifecycles"
                  border
                  size="mini"
                  :header-cell-style="{ background: '#fafafa' }"
                >
                  </el-table-column>
                  <el-table-column
                    prop="lifecycleNameCn"
                    label="生命周期中文名"
                    :show-overflow-tooltip="true"
                  >
                  </el-table-column>
                  <el-table-column
                    prop="lifecycleTime"
                    label="生命周期时间"
                    :show-overflow-tooltip="true"
                  >
                  </el-table-column>
                  <el-table-column prop="skuLifecycleStatus" label="生命周期状态">
                    <template slot-scope="scopes">
                      <el-tag v-if="scopes.row.skuLifecycleStatus === 0" type="danger">失效</el-tag>
                      <el-tag v-if="scopes.row.skuLifecycleStatus === 1" type="info">有效</el-tag>
                    </template>
                  </el-table-column>
                </el-table>
              </template>
            </el-table-column>
            <el-table-column
              prop="nationTwoAbbr"
              label="国家地区二位码"
              :show-overflow-tooltip="true"
            >
            </el-table-column>
            <el-table-column
              prop="nationNameCn"
              label="国家地区中文名"
              :show-overflow-tooltip="true"
            >
            </el-table-column>
            <el-table-column label="其他" :show-overflow-tooltip="true">
              <template slot-scope="scopeInner">
                <span style="color:#09F;cursor: pointer;" @click="expandTable(scopeInner.row)"
                  >生命周期</span
                >
              </template>
            </el-table-column>
          </el-table>
          <el-table
            v-show="scopeOut.row.extenShow"
            :data="scopeOut.row.extendAttributes"
            row-key="id"
            border
            size="mini"
            :header-cell-style="{ background: '#fafafa' }"
          >
            <el-table-column
              prop="attrValueCn"
              label="扩展属性值(中文)"
              :show-overflow-tooltip="true"
            >
            </el-table-column>
            <el-table-column
              prop="attrValueEn"
              label="扩展属性值(英文)"
              :show-overflow-tooltip="true"
            >
            </el-table-column>
            <el-table-column prop="valueDataType" label="数据类型">
              <template slot-scope="scopes">
                <el-tag v-if="scopes.row.valueDataType === 1" size="mini">字符串</el-tag>
                <el-tag v-if="scopes.row.valueDataType === 2" type="info" size="mini"
                  >带单位实数等</el-tag
                >
              </template>
            </el-table-column>
          </el-table>
        </template>
      </el-table-column>
      <el-table-column
        property="createTime"
        label="创建时间"
        :show-overflow-tooltip="true"
        :render-header="renderHeader"
      ></el-table-column>
      <el-table-column
        property="updateTime"
        label="更新时间"
        :show-overflow-tooltip="true"
        :render-header="renderHeader"
      ></el-table-column>
      <el-table-column label="其他" :show-overflow-tooltip="true" width="140">
        <template slot-scope="scopeOut">
          <span style="color:#09F;cursor: pointer;" @click="expandExTable(scopeOut.row)"
            >扩展属性</span
          >
          <span>|</span>
          <span style="color:#09F;cursor: pointer;" @click="expandCounTable(scopeOut.row)"
            >国家/地区</span
          >
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      class="pagination"
      :current-page="pageNum"
      :page-sizes="[10, 20, 30, 50]"
      :page-size="pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="total"
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
    >
    </el-pagination>
  </div>
</template>
<script>
import Crypto from '@/utils/crypto.js';
import diySelect from '@/components/Select/diySelect.vue';

export default {
  components: {
    diySelect,
  },
  data() {
    return {
      searchData: {},
      tableList: [],
      pageNum: 1,
      pageSize: 10,
      total: 0,
      loading: false,
      secretKey: '',
      pickerOptions: {
        shortcuts: [
          {
            text: '最近一周',
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit('pick', [start, end]);
            },
          },
          {
            text: '最近一个月',
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit('pick', [start, end]);
            },
          },
          {
            text: '最近三个月',
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
              picker.$emit('pick', [start, end]);
            },
          },
          {
            text: '最近六个月',
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 180);
              picker.$emit('pick', [start, end]);
            },
          },
        ],
      },
      dataList: [],
      expands: [],
      expandsCoun: [],
      lifeShow: false,
      countryShow: false,
      expandsInner: [], // 生命周期展开数组
      counFlag: true,
      colorCnsList: [],
      colorEnsList: [],
      colorLocalsList: [],
      carrierNameCnsList: [],
      carrierNameEnsList: [],
      certifiedModelsList: [],
    };
  },
  created() {
    this.getTableData('init');
    this.getSkuItem();
  },
  methods: {
    renderHeader(h, data) {
      return h('span', [
        h(
          'el-tooltip',
          {
            attrs: {
              class: 'item',
              effect: 'dark',
              content: data.column.label,
              placement: 'top',
            },
          },
          [h('span', data.column.label)]
        ),
      ]);
    },
    expandTable(row) {
      row.lifeShow = !row.lifeShow;
      if (row.lifeShow) {
        this.expandsInner.push(row.id);
      } else {
        this.expandsInner = this.expandsInner.filter(item => item !== row.id);
      }
      console.log(this.expandsInner, '生命周期');
    },
    expandCounTable(row) {
      row.countryShow = !row.countryShow;
      if (row.countryShow) {
        this.expands.push(row.skuId);
      } else {
        this.expands = this.expands.filter(item => item !== row.skuId);
      }
      row.extenShow = false;
      console.log(this.expands, '国家/地区');
    },
    expandExTable(row) {
      row.extenShow = !row.extenShow;
      if (row.extenShow) {
        this.expands.push(row.skuId);
      } else {
        this.expands = this.expands.filter(item => item !== row.skuId);
      }
      row.countryShow = false;
      console.log(this.expands, '扩展属性');
    },
    reset() {
      this.searchData = {};
      this.getTableData('init');
    },
    getTableData(init) {
      this.expandsInner = [];
      this.expands = [];
      let creatObj = {};
      if (this.searchData.createDate !== undefined && this.searchData.createDate !== null) {
        creatObj = {
          startCreateTime: this.searchData.createDate[0],
          endCreateTime: this.searchData.createDate[1],
        };
      } else {
        delete this.searchData.createDate;
        creatObj = {};
      }
      let updateObj = {};
      if (this.searchData.updateDate !== undefined && this.searchData.updateDate !== null) {
        updateObj = {
          startUpdateTime: this.searchData.updateDate[0],
          endUpdateTime: this.searchData.updateDate[1],
        };
      } else {
        delete this.searchData.updateDate;
        updateObj = {};
      }
      const obj = {
        skuIds: this.searchData.skuIds ? this.searchData.skuIds.split(/[(\r\n)\r\n]+/) : [],
        skuCodes: this.searchData.skuCodes ? this.searchData.skuCodes.split(/[(\r\n)\r\n]+/) : [],
        carrierIds: this.searchData.carrierIds
          ? this.searchData.carrierIds.split(/[(\r\n)\r\n]+/)
          : [],
        carrierCodes: this.searchData.carrierCodes
          ? this.searchData.carrierCodes.split(/[(\r\n)\r\n]+/)
          : [],
        normalizationIds: this.searchData.normalizationIds
          ? this.searchData.normalizationIds.split(/[(\r\n)\r\n]+/)
          : [],
        normalizationCodes: this.searchData.normalizationCodes
          ? this.searchData.normalizationCodes.split(/[(\r\n)\r\n]+/)
          : [],
        skuNameCn: this.searchData.skuNameCn,
        skuNameEn: this.searchData.skuNameEn,
        colorCns: this.searchData.colorCns,
        colorEns: this.searchData.colorEns,
        colorLocals: this.searchData.colorLocals,
        carrierNameCns: this.searchData.carrierNameCns,
        carrierNameEns: this.searchData.carrierNameEns,
        certifiedModels: this.searchData.certifiedModels,
        ...updateObj,
        ...creatObj,
      };
      if (init) {
        this.pageNum = 1;
        this.pageSize = 10;
      }
      this.loading = true;
      const param = {
        pageNum: this.pageNum,
        pageSize: this.pageSize,
        ...obj,
      };
      this.$api.productTree.skuList({ ...param }).then(res => {
        if (res.data) {
          this.tableList = res.data.content;
          this.tableList.forEach(item => {
            this.$set(item, 'countryShow', false);
            this.$set(item, 'extenShow', false);
          });
          this.total = res.data.total;
        }
        this.loading = false;
      });
    },
    handleCurrentChange(page) {
      this.pageNum = page;
      this.getTableData();
    },
    handleSizeChange(pageSize) {
      this.pageSize = pageSize;
      this.getTableData();
    },
    getSkuItem() {
      this.$api.productTree.skuItem().then(res => {
        if (res.data) {
          this.colorCnsList = [];
          this.colorEnsList = [];
          this.colorLocalsList = [];
          this.carrierNameCnsList = [];
          this.carrierNameEnsList = [];
          this.certifiedModelsList = [];
          for (const key in res.data) {
            const itemArr = [];
            res.data[key].forEach(item => {
              const obj = {
                name: item,
              };
              itemArr.push(obj);
            });
            if (key === 'colorCns') {
              this.colorCnsList = itemArr;
            } else if (key === 'colorEns') {
              this.colorEnsList = itemArr;
            } else if (key === 'colorLocals') {
              this.colorLocalsList = itemArr;
            } else if (key === 'carrierNameCns') {
              this.carrierNameCnsList = itemArr;
            } else if (key === 'carrierNameEns') {
              this.carrierNameEnsList = itemArr;
            } else if (key === 'certifiedModels') {
              this.certifiedModelsList = itemArr;
            }
          }
        }
      });
    },
  },
};
</script>
<style lang="scss" scoped>
.mainContent {
  margin: 20px;
}
.form-content {
  font-weight: 600;
}
.pagination {
  float: right;
  margin-top: 10px;
}
.import {
  margin: 0 0 20px 0;
}
.el-dialog .el-dialog__body {
  padding-top: 0 !important;
}
.el-form-item {
  margin-bottom: 15px !important;
}
.el-select,
.el-cascader,
.el-date-editor.el-input {
  width: 100%;
}
.searchBox >>> .el-form-item {
  display: flex;
  width: 100%;
  height: 30px;
  .el-form-item__label {
    white-space: nowrap;
  }
  .el-range-editor--mini.el-input__inner {
    height: 30px;
  }
  .el-form-item__content {
    flex: 1;
    .el-date-editor--daterange.el-input,
    .el-date-editor--daterange.el-input__inner,
    .el-date-editor--timerange.el-input,
    .el-date-editor--timerange.el-input__inner {
      width: 100% !important;
    }
  }
}
.tableBox >>> .el-table__expand-icon:after {
  content: '';
}
.tableBox >>> .el-table__expand-icon > i {
  display: none;
}
.tableBox >>> .el-table__expand-column {
  border-right: none;
}
</style>

 

posted @ 2021-01-13 16:53  棠樾  阅读(17605)  评论(3编辑  收藏  举报