<component :is=“ “/>动态组件在 el-tab-pane里的应用

添加新需求时翻到了以前的代码,之前选项卡有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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值