vue3+ts 封装echarts,根据tabs切换展示

 <div class="bottom">
                        <div class="topli">
                            <p>用电统计</p>
                            <div class="tabs">
                                <div class="tab" :class="{ active: active.tab1 === index }"
                                    v-for="(item, index) in tabsList1" :key="index" @click="changeTab(1, index)">
                                    {{ item.label }}
                                </div>
                            </div>
                        </div>
                        <div class="list">
                            <div id="sum-electricity" v-if="!loading.tab1 && active.tab1 === 0">
                                <TestEleChart pid="sum-electricity" title="月用电统计" :eleData="eleData"
                                    :eleXdata="eleXdata"></TestEleChart>
                            </div>
                            <div id="day-electricity" v-if="!loading.tab1 && active.tab1 === 1">
                                <TestEleChart pid="day-electricity" title="日用电统计" :eleData="eleData"
                                    :eleXdata="eleXdata"></TestEleChart>
                            </div>
                        </div>
                    </div>

                    <div class="sitestutus">
                        <div class="top">
                            <p>用水统计</p>
                            <div class="tabs">
                                <div class="tab" :class="{ active: active.tab2 === index }"
                                    v-for="(item, index) in tabsList" :key="index" @click="changeTab(2, index)">
                                    {{ item.label }}
                                </div>
                            </div>
                        </div>
                        <div class="sitebutom">
                            <div id="monthWate" v-if="!loading.tab2 && active.tab2 === 0">
                                <TestWaterChart pid="monthWate" title="月用水" :waterData="waterData"
                                    :waterXdata="waterXdata"></TestWaterChart>
                            </div>
                            <div id="dayWater" v-if="!loading.tab2 && active.tab2 === 1">
                                <TestWaterChart pid="dayWater" title="日用水" :waterData="waterData"
                                    :waterXdata="waterXdata"></TestWaterChart>
                            </div>

                        </div>
                    </div>

<script setup lang="ts">

// tabs切换

const tabsList = [

    { label: '日' },
    { label: '月' },
];

const tabsList1 = [

    { label: '日' },
    { label: '月' },
];

const active = ref({
    tab1: 0,
    tab2: 0,
});
const loading = ref({
    tab1: false,
    tab2: false,
});

const waterData = ref<number[]>([]);
const waterXdata = ref<string[]>([]);
const eleData = ref<number[]>([]);
const eleXdata = ref<string[]>([]);

// const loading = ref(false)
const fetchData = async (type: string, tabGroup: number) => {
    if (tabGroup === 1) {
        loading.value.tab1 = true;
        const store = siteStore();
        const res = await reqGetEleStatistics(store.curSite.id, type);
        eleXdata.value = res.data[type === 'day' ? 'elcWrDay' : 'elcWrMonth'].map((item: any) => item.createTime);
        eleData.value = res.data[type === 'day' ? 'elcWrDay' : 'elcWrMonth'].map((item: any) => item.value);
        if (eleData.value.length === 0) {
            eleXdata.value = ["无数据"];
            eleData.value = [0];
        }
        loading.value.tab1 = false;
    } else if (tabGroup === 2) {
        loading.value.tab2 = true;
        const store = siteStore();
        const res = await reqGetWaterStatistics(store.curSite.id, type);
        waterXdata.value = res.data[type === 'day' ? 'elcWrDay' : 'elcWrMonth'].map((item: any) => item.createTime);
        waterData.value = res.data[type === 'day' ? 'elcWrDay' : 'elcWrMonth'].map((item: any) => item.value);
        if (waterData.value.length === 0) {
            waterXdata.value = ["无数据"];
            waterData.value = [0];
        }
        loading.value.tab2 = false;
    }
};

const changeTab = async (tabGroup: number, index: number) => {
    if (tabGroup === 1) {
        active.value.tab1 = index;
        const type = index === 0 ? 'day' : 'month';
        await fetchData(type, tabGroup);
    } else if (tabGroup === 2) {
        active.value.tab2 = index;
        const type = index === 0 ? 'day' : 'month';
        await fetchData(type, tabGroup);
    }
};


// 初始化时获取数据
onMounted(async () => {
    await changeTab(1, active.value.tab1);
    await changeTab(2, active.value.tab2);
});

// scss
   .bottom {
                position: absolute;
                top: vh(635);
                width: vw(390);
                height: 400px;

                .topli {
                    display: flex;
                }

                p {

                    width: vw(435);
                    margin-left: vw(10);
                    line-height: vh(40);
                    color: #fff !important;
                   text-indent: 1rem;
                    font-weight: 700;
                    font-size: 25px;
                }

                #sum-electricity,
                #day-electricity {
                    width: vw(385);
                    height: vh(300);

                }

            }

            .sitestutus {
                position: absolute;
                top: vh(300);
                width: vw(385);
                height: 350px;


                p {
                    width: vw(435);
                    margin-left: vw(10);
                    line-height: vh(40);
                    color: #fff !important;
                    // background: linear-gradient(84deg, #1d4591 0%, rgba(57, 123, 243, 0) 100%) !important;
                    text-indent: 1rem;
                    font-weight: 700;
                    font-size: 25px;
                }

                .sitebutom {
                    color: #fff;
                    font-size: 20px;
                }

                #dayWater,
                #monthWate {
                    width: vw(385);
                    height: vh(300);

                }
            }

</script>

封装的 柱状图  组件 TestEleChart 

成品如图所示

<!-- 水电大屏用电趋势 -->
<template>
    <div>

    </div>
</template>

<script setup lang="ts">
import { nextTick, watch, computed, onMounted, ref, onUpdated, onBeforeUnmount } from 'vue';
import echarts from '@/assets/ts/echarts';
import { ZRColor } from 'echarts/types/dist/shared';
import useResizeChart from '@/components/CommonChart/hooks/useResizeChart';
import { color } from 'echarts';
import { EffectScatterChart } from 'echarts/charts';
echarts.use([EffectScatterChart]);

const props = defineProps({
    pid: {
        type: String,
        required: true,
    },
    title: {
        type: String,
        required: true,
    },
    // 饼图 颜色
    color: {
        type: Array as () => ZRColor[],
        default: [],
    },
    eleData: {
        type: Array,
        required: true,
    },
    // 横坐标值
    eleXdata: {
        type: Array,
        required: true,
    }
})

const sideData = props.eleData.map((item: any) => item + 7.5)

// nextTick(() => {
//     // 2. 容器
//     const container = document.querySelector('#' + props.pid) as HTMLElement;
//     if (container) renderChart(container);
// });
// // 3. 初始化 echarts 实例, 将配置添加给 echarts 实例
let myChart: echarts.ECharts | null = null;
// const renderChart = (container?: HTMLElement) => {
//     if (!myChart) {
//         myChart = echarts.init(container as HTMLElement);
//         // 自适应 chart
//         useResizeChart(container as HTMLElement, myChart as echarts.ECharts);
//     }

//     myChart.setOption(option);
// };
// 改进
const initChart = async () => {
    await nextTick();  // 确保 DOM 更新完成
    const container = document.querySelector('#' + props.pid) as HTMLElement;
    if (container) {
        myChart = echarts.init(container);
        // 自适应 chart
        // @ts-ignore
        useResizeChart(container as HTMLElement, myChart);
        renderChart();
    }
}


// 4.配置项
const renderChart = () => {
    if(!myChart) return;
    const option = {

        backgroundColor: 'transparent',
        tooltip: {
            trigger: 'axis',
            formatter: "{b} : {c}",
            axisPointer: { // 坐标轴指示器,坐标轴触发有效
                type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
            }
        },
        xAxis: {
            data: props.eleXdata,
            //坐标轴
            axisLine: {
                lineStyle: {
                    color: '#3eb2e8'
                }
            },
            //坐标值标注
            axisLabel: {
                show: true,
                textStyle: {
                    color: '#fff',
                }
            }
        },
        yAxis: {
            //坐标轴
            axisLine: {
                show: false
            },
            //坐标值标注
            axisLabel: {
                show: true,
                textStyle: {
                    color: '#fff',
                }
            },
            //分格线
            splitLine: {
                lineStyle: {
                    color: '#4784e8'
                }
            }
        },
        series: [{
            name: 'a',
            tooltip: {
                show: false
            },
            type: 'bar',
            // 柱子的宽度
            barWidth: 15,
            itemStyle: {
                normal: {
                    color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
                        offset: 0,
                        color: "#0B4EC3" // 0% 处的颜色
                    }, {
                        offset: 0.6,
                        color: "#138CEB" // 60% 处的颜色
                    }, {
                        offset: 1,
                        color: "#17AAFE" // 100% 处的颜色
                    }], false)
                }
            },
            data: props.eleData,
            barGap: 0
        }, {
            type: 'bar',
            barWidth: 8,
            itemStyle: {
                normal: {
                    color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
                        offset: 0,
                        color: "#09337C" // 0% 处的颜色
                    }, {
                        offset: 0.6,
                        color: "#0761C0" // 60% 处的颜色
                    }, {
                        offset: 1,
                        color: "#0575DE" // 100% 处的颜色
                    }], false)
                }
            },
            barGap: 0,
            data: sideData
        }, {
            name: 'b',
            tooltip: {
                show: false
            },
            type: 'pictorialBar',
            itemStyle: {
                borderWidth: 0,
                borderColor: '#0571D5',
                color: '#1779E0'
            },
            symbol: 'path://M 0,-10 l 110,0 l -12,85 l -110,0 z',
            // key[0]为盖子宽度 key[1]为倾斜程度 值小倾斜小
            symbolSize: ['23', '8'],
            // key[1] y轴
            symbolOffset: ['0', '-8'],
            //symbolRotate: -5,
            symbolPosition: 'end',
            data: props.eleData,
            z: 3
        }]

    };
    myChart.setOption(option);
}
onMounted(initChart);

onBeforeUnmount(() => {
  if (myChart) {
    myChart.dispose();
    myChart = null;
  }
});

watch(
  [() => props.eleData, () => props.eleXdata],
  () => {
    renderChart();
  },
  { deep: true }
);
</script>

<style scoped></style>

封装的 柱状图  组件 TestEleChart 

成品如图所示

<!-- 水务大屏柱状图 -->
<template>
    <div :id="props.pid" style="width: 100%; height: 100%;"></div>
  </template>

  <script setup lang="ts">
  import { nextTick, watch, ref, onMounted, onBeforeUnmount } from 'vue';
  import * as echarts from 'echarts';
  import { ZRColor } from 'echarts/types/dist/shared';
  import useResizeChart from '@/components/CommonChart/hooks/useResizeChart';

  const props = defineProps({
    pid: {
      type: String,
      required: true,
    },
    title: {
      type: String,
      required: true,
    },
    color: {
      type: Array as () => ZRColor[],
      default: () => [],
    },
    waterData: {
      type: Array,
      required: true,
    },
    waterXdata: {
      type: Array,
      required: true,
    }
  });

  let myChart: echarts.ECharts | null = null;

  const initChart = async () => {
    await nextTick();  // 确保 DOM 更新完成
    const container = document.querySelector('#' + props.pid) as HTMLElement;
    if (container) {
      myChart = echarts.init(container);
      // 自适应 chart
      // @ts-ignore
      useResizeChart(container as HTMLElement, myChart);
      renderChart();
    }
  };

  const renderChart = () => {
    if (!myChart) return;
    const option = {
      backgroundColor: "transparent",
      color: ["#3cefff"],
      tooltip: {},
      grid: {
        containLabel: true,
      },
      xAxis: [
        {
          type: "category",
          data: props.waterXdata,
          axisTick: {
            alignWithLabel: true,
          },
          nameTextStyle: {
            color: "#82b0ec",
          },
          axisLine: {
            lineStyle: {
              color: "#82b0ec",
            },
          },
          axisLabel: {
            textStyle: {
              color: "#82b0ec",
            },
          },
        },
      ],
      yAxis: [
        {
          type: "value",
          axisLabel: {
            textStyle: {
              color: "#82b0ec",
            },
            formatter: "{value}%",
          },
          splitLine: {
            lineStyle: {
              color: "#0c2c5a",
            },
          },
          axisLine: {
            show: false,
          },
        },
      ],
      series: [
        {
          name: "",
          type: "pictorialBar",
          symbolSize: [20, 10],
          symbolOffset: [0, -5],
          symbolPosition: "end",
          z: 12,
          label: {
            show: true,
            position: "top",
            formatter: "{c}%",
          },
          data: props.waterData,
        },
        {
          name: "",
          type: "pictorialBar",
          symbolSize: [20, 10],
          symbolOffset: [0, 5],
          z: 12,
          data: props.waterData,
        },
        {
          type: "bar",
          itemStyle: {
            opacity: 0.7,
          },
          barWidth: "20",
          data: props.waterData,
          markLine: {
            silent: true,
            symbol: "none",
            label: {
              position: "middle",
              formatter: "{b}",
            },
            data: [
              {
                name: "目标值",
                yAxis: 80,
                lineStyle: {
                  color: "#ffc832",
                },
                label: {
                  position: "end",
                  formatter: "{b}\n {c}%",
                },
              },
            ],
          },
        },
        {
          type: "effectScatter",
          silent: true,
          tooltip: {
            show: false,
          },
          zlevel: 3,
          symbolSize: 10,
          showEffectOn: "render",
          rippleEffect: {
            brushType: "stroke",
            color: "#3cefff",
            scale: 5,
          },
          itemStyle: {
            color: "#3cefff",
          },
          hoverAnimation: true,
          data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0,0,0,0],
        },
      ],
    };
    myChart.setOption(option);
  };

  onMounted(initChart);

  onBeforeUnmount(() => {
    if (myChart) {
      myChart.dispose();
      myChart = null;
    }
  });

  watch(
    [() => props.waterData, () => props.waterXdata],
    () => {
      renderChart();
    },
    { deep: true }
  );
  </script>

  <style scoped>
  /* 样式代码 */
  </style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值