基于vue3-elemenyui的动态列案例
本案例主要是实现数据模型的解析以及实现el-table的动态列加载。
1.数据结构
公司A\B\C\测试1,是列,功能-url,是行数据,其中功能x是行头。
this.rawData = [{companyName: "公司A",rpWebShows: [{ "功能1": "https://map.baidu.com/" },{ "功能2": "https://map.baidu.com/" },{ "功能3": "https://map.baidu.com/" }]},{companyName: "公司B",rpWebShows: [{ "功能1": "https://map.baidu.com/" },{ "功能3": "https://map.baidu.com/" },{ "功能4": "https://map.baidu.com/" }]},{companyName: "公司C",rpWebShows: [{ "功能2": "https://map.baidu.com/" },{ "功能3": "https://map.baidu.com/" },{ "功能5": "https://map.baidu.com/" }]},{companyName: "测试1",rpWebShows: [{ "功能1": "https://map.baidu.com/" },{ "功能2": "https://map.baidu.com/" },{ "功能5": "https://map.baidu.com/" }]}]this.companyList = this.rawData.map(item => item.companyName).filter(company => !this.companyList2.includes(company))this.displayCompanyList = [...this.companyList]this.filteredData = this.rawDatathis.loading = false},
2.初始化el-table
采用v-solt的定义el-table内的结构,并命名为scope,采用v-for语法,实现将companyList2和displayCompanyList内的数据,转换为列。
<el-table v-loading="loading" border :data="tableData" style="width: 100%" :header-cell-style="{background:'#f5f7fa',color:'#606266'}"><el-table-column prop="functionName" label="功能名称" width="120" fixed/><el-table-column prop="functionName2" label="功能名称2" width="120" fixed/><!-- 动态渲染测试列(companyList2) --><el-table-column v-for="(label, index) in companyList2" :key="index" :label="label" :width="120"><template v-slot="scope"><div class="clickable-cell2" @click="handleCellClick(scope.row.functionName, label, scope.row[`test${index + 1}`])">{{ scope.row[`test${index + 1}`] || '/' }}</div></template></el-table-column><el-table-column v-for="company in displayCompanyList" :key="company" :label="company" :prop="company"><template v-slot="scope"><div v-if="scope.row[company]" class="clickable-cell" @click="openContentWindow(scope.row.functionName, company, scope.row[company])">{{ scope.row[company] }}</div><div v-else>-</div></template></el-table-column></el-table>
3.数据解析
computed: {tableData() {const data = this.filteredData !== null ? this.filteredData : this.rawDataif (!data || !Array.isArray(data)) return []const allFunctions = new Set()data.forEach(company => {if (company.rpWebShows && Array.isArray(company.rpWebShows)) {company.rpWebShows.forEach(item => {const functionName = Object.keys(item)[0]if (functionName) allFunctions.add(functionName)})}})this.functionList = Array.from(allFunctions)const result = []this.functionList.forEach(func => {const row = { functionName: func, functionName2: `${func}2` }this.companyList2.forEach((label, index) => {const testCompanyData = data.find(item => item.companyName === label)if (testCompanyData && testCompanyData.rpWebShows) {const funcData = testCompanyData.rpWebShows.find(item => Object.keys(item)[0] === func)row[`test${index + 1}`] = funcData ? funcData[func] : null} else {row[`test${index + 1}`] = null}})this.displayCompanyList.forEach(company => {const companyData = data.find(item => item.companyName === company)if (companyData && companyData.rpWebShows) {const funcData = companyData.rpWebShows.find(item => Object.keys(item)[0] === func)row[company] = funcData ? funcData[func] : null} else {row[company] = null}})result.push(row)})return result}}
4.附件1(数据模型)
<template><div class="app-container"><div style="margin-bottom: 16px; display: flex; align-items: center;"><span style="margin-right: 8px;">公司名称</span><el-select v-model="searchCompany" placeholder="请选择" clearable style="width: 200px; margin-right: 8px;"><el-optionv-for="company in companyList":key="company":label="company":value="company"/></el-select><el-button type="primary" @click="handleSearch">搜索</el-button><el-button @click="handleReset" style="margin-left: 8px;">重置</el-button></div><el-table v-loading="loading" :data="tableData" border style="width: 100%":header-cell-style="{background:'#f5f7fa',color:'#606266'}"><el-table-column prop="functionName" label="功能名称" width="120" fixed/><el-table-column v-for="company in displayCompanyList" :key="company" :label="company" :prop="company"><template v-slot="scope"><div v-if="scope.row[company]" class="clickable-cell" @click="openContentWindow(scope.row.functionName, company, scope.row[company])">{{ scope.row[company] }}</div><div v-else></div></template></el-table-column></el-table></div>
</template><script>
export default {name: "FunctionUrlMatrix",data() {return {loading: false,companyList: [],functionList: [],rawData: null,searchCompany: '',filteredData: null,displayCompanyList: []}},computed: {tableData() {const data = this.filteredData !== null ? this.filteredData : this.rawData;if (!data) return [];const result = []; this.functionList.forEach(func => {const row = { functionName: func };this.companyList.forEach(company => {const companyData = data.find(item => item.companyName === company);if (companyData && companyData.rpWebShows) {const funcData = companyData.rpWebShows.find(item => item.requestName === func);row[company] = funcData ? funcData.requestUrl : null;} else {row[company] = null;}});result.push(row);});return result;}},created() {this.loadData();},methods: {loadData() {this.loading = true;// 使用本地模拟数据替代API请求this.rawData = [{companyName: "公司A",rpWebShows: [{ requestName: "功能1", requestUrl: "https://company-a.com/func1" },{ requestName: "功能2", requestUrl: "https://company-a.com/func2" },{ requestName: "功能3", requestUrl: "https://company-a.com/func3" }]},{companyName: "公司B",rpWebShows: [{ requestName: "功能1", requestUrl: "https://company-b.com/func1" },{ requestName: "功能3", requestUrl: "https://company-b.com/func3" },{ requestName: "功能4", requestUrl: "https://company-b.com/func4" }]},{companyName: "公司C",rpWebShows: [{ requestName: "功能2", requestUrl: "https://company-c.com/func2" },{ requestName: "功能3", requestUrl: "https://company-c.com/func3" },{ requestName: "功能5", requestUrl: "https://company-c.com/func5" }]}];this.extractCompanyAndFunctionList();this.loading = false;this.filteredData = this.rawData;},extractCompanyAndFunctionList() {if (!this.rawData || !Array.isArray(this.rawData)) {console.error('无效的数据结构:', this.rawData);return;}this.companyList = this.rawData.map(item => item.companyName).filter(Boolean);this.displayCompanyList = [...this.companyList];const allFunctions = new Set();this.rawData.forEach(company => {if (company.rpWebShows && Array.isArray(company.rpWebShows)) {company.rpWebShows.forEach(func => {if (func && func.requestName) {allFunctions.add(func.requestName);}});console.log(allFunctions);} else {console.warn('公司数据缺少rpWebShows或格式不正确:', company);}});this.functionList = Array.from(allFunctions);console.log("111111111");console.log(this.functionList);},handleSearch() {if (!this.searchCompany) {this.filteredData = this.rawData;this.displayCompanyList = [...this.companyList];return;}this.filteredData = this.rawData.filter(item => item.companyName === this.searchCompany);this.displayCompanyList = [this.searchCompany];},handleReset() {this.searchCompany = '';this.filteredData = this.rawData;this.displayCompanyList = [...this.companyList];},openContentWindow(functionName, company, url) {// 实际环境中使用路由,这里改为直接打开URLwindow.open(url, '_blank');}}
}
</script><style scoped>
.el-table {margin-top: 20px;
}
.el-link {margin-right: 10px;
}.clickable-cell {color: #1890ff;cursor: pointer;text-decoration: underline;
}.clickable-cell:hover {color: #40a9ff;
}
</style>
5.附件2(数据字典)
<template><div class="app-container"><div style="margin-bottom: 16px; display: flex; align-items: center;"><span style="margin-right: 8px;">公司名称</span><el-select v-model="searchCompany" placeholder="请选择" clearable style="width: 200px; margin-right: 8px;"><el-optionv-for="company in companyList":key="company":label="company":value="company"/></el-select><el-button type="primary" @click="handleSearch">搜索</el-button><el-button @click="handleReset" style="margin-left: 8px;">重置</el-button></div><el-table v-loading="loading" :data="tableData" border style="width: 100%":header-cell-style="{background:'#f5f7fa',color:'#606266'}"><el-table-column prop="functionName" label="功能名称" width="120" fixed/><el-table-column v-for="company in displayCompanyList" :key="company" :label="company" :prop="company"><template v-slot="scope"><div v-if="scope.row[company]" class="clickable-cell" @click="openContentWindow(scope.row.functionName, company, scope.row[company])">{{ scope.row[company] }}</div><div v-else></div></template></el-table-column></el-table></div>
</template><script>
export default {name: "FunctionUrlMatrix",data() {return {loading: false,companyList: [],functionList: [],rawData: null,searchCompany: '',filteredData: null,displayCompanyList: []}},computed: {tableData() {const data = this.filteredData !== null ? this.filteredData : this.rawData;if (!data) return [];const result = []; this.functionList.forEach(func => {const row = { functionName: func };this.companyList.forEach(company => {const companyData = data.find(item => item.companyName === company);if (companyData && companyData.rpWebShows) {// 保持原始数据结构不变,从对象中提取功能名称和URLconst funcData = companyData.rpWebShows.find(item => {const key = Object.keys(item)[0];return key === func;});row[company] = funcData ? funcData[func] : null;} else {row[company] = null;}});result.push(row);});return result;}},created() {this.loadData();},methods: {loadData() {this.loading = true;// 使用原始数据结构,不做修改this.rawData = [{companyName: "公司A",rpWebShows: [{ "功能1": "https://company-a.com/func1" },{ "功能2": "https://company-a.com/func2" },{ "功能3": "https://company-a.com/func3" }]},{companyName: "公司B",rpWebShows: [{ "功能1": "https://company-b.com/func1" },{ "功能3": "https://company-b.com/func3" },{ "功能4": "https://company-b.com/func4" }]},{companyName: "公司C",rpWebShows: [{ "功能2": "https://company-c.com/func2" },{ "功能3": "https://company-c.com/func3" },{ "功能5": "https://company-c.com/func5" }]}];this.extractCompanyAndFunctionList();this.loading = false;this.filteredData = this.rawData;},extractCompanyAndFunctionList() {if (!this.rawData || !Array.isArray(this.rawData)) {console.error('无效的数据结构:', this.rawData);return;}this.companyList = this.rawData.map(item => item.companyName).filter(Boolean);this.displayCompanyList = [...this.companyList];const allFunctions = new Set();this.rawData.forEach(company => {if (company.rpWebShows && Array.isArray(company.rpWebShows)) {company.rpWebShows.forEach(func => {// 从对象结构中提取功能名称const functionName = Object.keys(func)[0];if (functionName) {allFunctions.add(functionName);}});} else {console.warn('公司数据缺少rpWebShows或格式不正确:', company);}});this.functionList = Array.from(allFunctions);},handleSearch() {if (!this.searchCompany) {this.filteredData = this.rawData;this.displayCompanyList = [...this.companyList];return;}this.filteredData = this.rawData.filter(item => item.companyName === this.searchCompany);this.displayCompanyList = [this.searchCompany];},handleReset() {this.searchCompany = '';this.filteredData = this.rawData;this.displayCompanyList = [...this.companyList];},openContentWindow(functionName, company, url) {window.open(url, '_blank');}}
}
</script><style scoped>
.el-table {margin-top: 20px;
}
.el-link {margin-right: 10px;
}.clickable-cell {color: #1890ff;cursor: pointer;text-decoration: underline;
}.clickable-cell:hover {color: #40a9ff;
}
</style>