項目需求:要求點擊行中的“其他”單元格中的字段展開相應的子表
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>
