添加新需求时翻到了以前的代码,之前选项卡有2项,就不辞辛苦的直接写template里了。这次又新增了两个选项卡页面。于是将以前的结构翻出来直接写循环了。代码在最后面,没什么参考价值可以忽略。
本篇的目的:主要是写完后,发现此页面还有一个选项卡页面,用来切换不同的组件。(后期又被需求拿掉了,但是页面上没删。)本着代码一致的原则,就手贱的改了下。这个项目用的是element UI。在用 el-tabs数据循环的时候,如果不在el-tab-pane的结构中写DOM,最后输出的是一个字符串。尝试了一些方法后,最后用<component :is="item.content" />解决了。具体代码如下图。vue 动态组件
<template>
<div class="app-container">
<section v-if="false">
<h2 id="tab" class="trendTitle">辅助分析工具</h2>
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
<template v-for="item in auxiliaryTool">
<!-- 额外增加v-if="true",不加:key标红 -->
<el-tab-pane v-if="true" :key="item.name" :label="item.title" :name="item.name">
<div v-if="item.isShow">
<component :is="item.content" />
</div>
</el-tab-pane>
</template>
</el-tabs>
</section>
</div>
</template>
<script>
import CrossArea from '@/views/smart/crossarea/crossarea';
import Inout from '@/views/smart/inout/inout';
import Quadif from '@/views/smart/quadif/quadif';
export default {
name: 'Trend',
components: {
CrossArea,
Inout,
Quadif,
BasisStructure,
TermStructure,
},
data() {
return {
activeName: '',
auxiliaryTool: [
{
title: '跨1',
name: 'crossArea',
content: CrossArea,
isShow: false,
},
{
title: '内2',
name: 'inout',
content: Inout,
isShow: false,
},
{
title: '品3',
name: 'quadif',
content: Quadif,
isShow: false,
},
],
};
},
methods: {
handleClick(val) {
this.auxiliaryTool = this.auxiliaryTool.map(item => {
if (item.name === val.name) {
item.isShow = true;
} else {
item.isShow = false;
}
return item;
});
this.$nextTick(() => {
document.getElementById('tab').scrollIntoView({
behavior: 'smooth',
block: 'start',
});
});
},
},
};
</script>
本文完,以下纯记录,懒得开新文了。
记录v-for循环el-tab-pane代码
<template>
<div class="app-container">
<section v-loading="loading">
<el-row :gutter="20">
<el-col :span="activeChart === 'first' || activeChart === 'second' ? 16 : 24">
<h3 class="chartTitle">{{ chartTitle }}</h3>
<el-tabs v-model="activeChart" type="card" @tab-click="handleClick2">
<template v-for="item in tabs">
<el-tab-pane v-if="item.hasOwnProperty('isPer') ? item.isPer : true" :key="item.name" :label="item.title" :name="item.name">
<div v-if="activeChart === item.name">
<line-chart v-show="ChartBoxShow" :chart-data="lineChartData" :height="chartHeight" />
<el-empty v-show="!ChartBoxShow" description="暂无数据" />
</div>
</el-tab-pane>
</template>
</el-tabs>
</el-col>
<el-col v-if="activeChart === 'first' || activeChart === 'second'" v-hasPermi="['price:trend:query']" :span="8">
<div v-dompurify-html.trim="coalAnalyze" class="artitle" :style="{ height: chartHeight }" />
</el-col>
<el-col v-if="activeChart === 'first' || activeChart === 'second'" v-hasPermi="['price:trend:query']" :span="24" class="explainBox">
<div v-dompurify-html.trim="coalExplain" class="artitle" />
</el-col>
</el-row>
</section>
</div>
</template>
<script>
import LineChart from '@/components/Echarts/LineCharts';
import { coalIndex, getGraph, getGraph2, getPreIindex, getReport } from '@/api/trend';
import { debounce, getTime, setMyOpts, sortSeriesByMaxValue } from '@/utils/global.js';
export default {
name: 'Trend',
components: {
LineChart,
},
data() {
return {
loading: true, // 遮罩层
isPer: false, //判断是否具有某个权限
// 图表
chartTitle: '标题',
chartHeight: '0', //设置图表高度
lineChartData: {}, // 图表数据
ChartBoxShow: true, //图表有无数据,是否显示
// 解释文字/后台输出的文字内容
coalAnalyze: '',
coalExplain: '',
// 选项卡
activeChart: this.isPer ? 'second' : 'three',
tabs: [
{
title: '总预测趋势图',
name: 'first',
isPer: false,
},
{
title: '区间预测图',
name: 'second',
isPer: false,
},
{
title: '预测指数图',
name: 'three',
},
{
title: '周环比分析图',
name: 'four',
},
],
};
},
computed: {
permissions() {
return this.$store.getters.permissions;
},
},
watch: {
isPer: {
handler: function(newVal) {
this.tabs = this.tabs.map(item => {
if (item.hasOwnProperty('isPer')) {
item['isPer'] = newVal;
}
return item;
});
},
deep: true,
},
},
created() {
this.isPer = this.permissions.some(permission => {
return '*:*:*' === permission || ['price:trend:query'].includes(permission);
});
this.activeChart = this.isPer ? 'second' : 'three';
// 设置图表高度
this.setChartHeight();
// 提交表单
this.getSubmit(this.queryParams);
this.getSubmit = debounce(function(data) {
this.handleClick2({ name: this.activeChart });
getReport().then(res => {
this.coalExplain = res.data
.map(item => {
if (!item.title.includes('分析')) {
return `
<h3>${item.title.includes('、') ? item.title.split('、')[1] : item.title}</h3>
<p>${item.desc.replace(/\r\n/gm, '<br/>')}</p>
`;
}
})
.join('');
this.coalAnalyze = res.data
.map(item => {
if (item.title.includes('分析')) {
return `
<h3>${item.title.includes('、') ? item.title.split('、')[1] : item.title}</h3>
<p>${item.desc.replace(/\r\n/gm, '<br/>')}</p>
`;
}
})
.join('');
});
});
},
methods: {
handleClick2(val) {
let obj = {
first: {
title: '1',
api: getGraph,
},
second: {
title: '1',
api: getGraph2,
},
three: {
title: '2',
api: getPreIindex,
},
four: {
title: '3',
api: getPreIindex,
},
// four: () => {
// return new Promise(async resolve => {
// this.chartTitle = '周环比分析';
// this.loading = true;
// let res = getPreIindex();
// resolve(res);
// });
// },
};
if (!obj[val.name].title || !obj[val.name].api) {
return;
}
this.getCharts(obj[val.name].title, obj[val.name].api).then(({ res, title }) => {
this.loading = false;
this.chartTitle = title;
this.ChartBoxShow = res['data'] ? true : false;
if (this.ChartBoxShow) {
let myChart = this.$store.state.echarts.init[0];
const customObj = {
first: {
title: {
subtext: '',
},
legend: {
top: '34px',
right: 'auto',
orient: 'horizontal',
},
grid: {
width: '72%',
top: '76px',
left: '38',
},
series: item => {
if (item.type === 'scatter') {
if (typeof item.label.formatter == 'string') {
return {
color: 'rgb(231,90,110)',
label: {
backgroundColor: 'rgba(231,90,110,.3)',
},
labelLayout: {
with: 160,
x: myChart.getWidth() - 120,
draggable: true,
verticalAlign: 'middle',
},
markPoint: null,
markLine: null,
};
}
return {
labelLayout() {
return {
width: typeof item.label.formatter == 'string' ? 160 : 140,
x: myChart.getWidth() - 120,
draggable: true,
verticalAlign: 'middle',
};
},
markPoint: null,
markLine: null,
};
} else {
if (item.name.includes('动力煤连续合约')) {
return {
markLine: null,
markPoint: {
symbol: 'circle',
symbolSize: 10,
label: {
show: false,
},
},
};
}
return {
markPoint: null,
markLine: null,
};
}
},
},
second: {
legend: {
top: '48px',
right: 'auto',
orient: 'horizontal',
},
grid: {
width: '72%',
top: '76px',
left: '38',
},
series: item => {
if (item.type === 'scatter') {
if (typeof item.label.formatter == 'string') {
return {
color: 'rgb(231,90,110)',
label: {
backgroundColor: 'rgba(231,90,110,.3)',
},
labelLayout: {
with: 160,
x: myChart.getWidth() - 120,
draggable: true,
verticalAlign: 'middle',
},
markPoint: null,
markLine: null,
};
}
return {
labelLayout: {
with: 140,
x: myChart.getWidth() - 120,
draggable: true,
verticalAlign: 'middle',
},
markPoint: null,
markLine: null,
};
} else {
if (item.name.includes('动力煤连续合约')) {
return {
markLine: null,
markPoint: {
symbol: 'circle',
symbolSize: 10,
label: {
show: false,
},
},
};
}
if (item.name.includes('预测值上限') || item.name.includes('预测值下限')) {
return {
itemStyle: {
color: '#aaaaaa',
borderColor: '#aaaaaa',
},
lineStyle: {
color: '#aaaaaa',
},
markPoint: null,
markLine: null,
};
}
return {
markPoint: null,
markLine: null,
};
}
},
},
three: {
legend: {
top: '48px',
right: 'auto',
orient: 'horizontal',
},
grid: {
width: '96%',
top: '76px',
left: '38',
},
yAxis: [
{
name: '',
},
],
series: item => {
if (item.type === 'scatter') {
return {
labelLayout: {
with: 140,
x: myChart.getWidth() - 120,
draggable: true,
verticalAlign: 'middle',
},
markPoint: null,
markLine: null,
};
} else {
return {
markPoint: null,
markLine: null,
};
}
},
},
four: {
legend: {
top: '48px',
right: 'auto',
orient: 'horizontal',
},
grid: {
width: '96%',
top: '76px',
left: '38',
},
yAxis: [
{
name: '',
},
],
series: item => {
if (item.type === 'scatter') {
return {
labelLayout: {
with: 140,
x: myChart.getWidth() - 120,
draggable: true,
verticalAlign: 'middle',
},
markPoint: null,
markLine: null,
};
} else {
return {
markPoint: null,
markLine: null,
};
}
},
},
};
let custom = customObj[val.name];
this.lineChartData = setMyOpts(sortSeriesByMaxValue(res['data']), custom);
}
});
},
getCharts(title, api) {
return new Promise(async resolve => {
if (typeof api == 'function') {
this.loading = true;
let res = await api();
resolve({ res, title });
}
});
},
setChartHeight() {
// 设置图表高度
let halfWidth = (document.documentElement.clientWidth / 2) * 0.74;
this.chartHeight = (halfWidth / 4) * 3 + 'px';
window.onresize = () => {
return (() => {
halfWidth = (document.documentElement.clientWidth / 2) * 0.74;
this.chartHeight = (halfWidth / 4) * 3 + 'px';
})();
};
},
},
};
</script>
<style lang="scss" scoped>
@import '@/assets/styles/explain.scss';
.chartTitle {
text-align: center;
@include themeify {
color: themed('main-font-color');
}
}
.formBox {
margin: 0 0 30px;
}
.explainBox {
margin-top: 30px;
}
::v-deep .artitle {
margin-top: 0;
font-size: 16px;
}
::v-deep .artitle h3 {
margin: 6px auto 14px;
text-indent: 0;
font-size: 24px;
// font-weight: normal;
}
::v-deep .artitle p {
width: 98%;
line-height: 2;
margin: 10px auto;
text-indent: 0;
}
.trendTitle {
margin: 50px 0 20px;
text-align: left;
@include themeify {
color: themed('main-font-color');
}
}
.rangeSeparator {
display: inline-block;
height: 100%;
padding: 0 5px;
margin: 0;
text-align: center;
line-height: 32px;
font-size: 14px;
width: 5%;
@include themeify {
color: themed('main-font-color');
}
}
</style>