Vue 中对 Echart 的多次封装

在使用 Vue 的 Echart 开发中,经常需要绘制不同的图表,因此,可以将 Echart 的公用部分进行多次封装,通过 vue 的 watch 机制,逐步具化最终的图表,以达到便捷简单通用的效果。也体现了职责单一的设计理念

效果图:

在这里插入图片描述

分析:

结合效果图,可以拆分成上下两部分,上面由 Echart 组件构成,下面由 dataV 的数字翻牌器组成。本文主要讲述上面的封装。

代码:

  • 对 Echart 的第一次封装,暴露出各种的属性,并监听 options 属性的变化,CommonEchart.vue

    <template>
        <div
            :id="id"
            :class="className"
            :style="{ height: height, width: width }"
        />
    </template>
    <script>
        export default {
            // 设置图表的属性
            props: {
                id: {
                    type: String,
                    default: 'chart',
                },
                className: {
                    type: String,
                    default: 'chart',
                },
                width: {
                    type: String,
                    default: '100%',
                },
                height: {
                    type: String,
                    default: '2.5rem',
                },
                options: {
                    type: Object,
                    default: () => ({}),
                },
            },
            data() {
                return {
                    chart: null,
                }
            },
            watch: {
                // 监听图表的options属性
                options: {
                    handler(newVal, oldVal) {
                        // 设置新的数据,并清空echart缓存
                        this.chart.setOption(newVal, true)
                    },
                    // 深度监听(监听组件内部的变化,用于多层组件嵌套)
                    deep: true,
                },
            },
            mounted() {
                this.initChart()
            },
            beforeDestroy() {
                this.chart.dispose()
                this.chart = null
            },
            methods: {
                initChart() {
                    // 初始化图表
                    this.chart = this.$echarts.init(this.$el)
                    // 设置图表数据
                    this.chart.setOption(this.options, true)
                },
            },
        }
    </script>
    
  • 对 Echart 的第二次封装,设置属性,并定义新的数据属性 chartData,从而监听 chartData,完成 options 的具体化,Pie.vue

    <template>
        <CommonEchart :options="options" height="220px" width="260px" />
    </template>
    <script>
        // 导入公用的图表
        import CommonEchart from '../echart/CommonEchart.vue'
        export default {
            components: {
                CommonEchart,
            },
            // 定义当前组件属性,用于后面的监听
            props: {
                chartData: {
                    type: Object,
                    default: () => ({}),
                },
            },
            data() {
                return {
                    options: {},
                }
            },
            watch: {
                // 监听属性chartData,当数据变化时,更新图表的数据(options)
                chartData: {
                    handler(newVal, oldVal) {
                        this.options = {
                            color: [
                                '#37a2da',
                                '#32c5e9',
                                '#9fe6b8',
                                '#ffdb5c',
                                '#ff9f7f',
                                '#fb7293',
                            ],
                            tooltip: {
                                trigger: 'item',
                                // 饼图、仪表盘、漏斗图: {a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)
                                formatter: '{a} <br/>{b} : {c} ({d}%)',
                            },
                            toolbox: {
                                show: true,
                            },
                            calculable: true,
                            legend: {
                                orient: 'horizontal',
                                icon: 'circle',
                                bottom: 0,
                                x: 'center',
                                data: newVal.xData,
                                textStyle: {
                                    color: '#fff',
                                },
                            },
                            series: [
                                {
                                    type: 'pie',
                                    name: '分布统计',
                                    radius: [5, 40],
                                    roseType: 'radius',
                                    center: ['50%', '40%'],
                                    data: newVal.seriesData,
                                },
                            ],
                        }
                    },
                    // 立刻更新图表内容
                    immediate: true,
                    // 深度监听(监听组件内部的变化,用于多层组件嵌套)
                    deep: true,
                },
            },
        }
    </script>
    
  • 最终应用到父组件中(设置 chartData 属性),PieData.vue

    <template>
        <div class="container">
            <div class="bg-color-black">
                <div class="d-flex pt-2 pl-2">
                    <div class="d-flex">
                        <span class="fs-xl text mx-2">任务通过率</span>
                    </div>
                </div>
                <div class="d-flex jc-center">
                    <!-- 使用组件并绑定属性,从而完成图表的展示 -->
                    <Pie :chartData="chartData" />
                </div>
                <!-- 4个主要的数据 -->
                <div class="bottom-data">
                    <div
                        class="item-box mt-2"
                        v-for="(item, index) in numberData"
                        :key="index"
                    >
                        <div class="d-flex">
                            <span class="coin"></span>
                            <dv-digital-flop
                                class="dv-digital-flop"
                                :config="item.number"
                            />
                        </div>
                        <p class="text" style="text-align: center;">
                            {{ item.text }}
                        </p>
                    </div>
                </div>
            </div>
        </div>
    </template>
    <script>
        // 导入第二次封装的组件
        import Pie from './pie/Pie.vue'
        export default {
            components: {
                Pie,
            },
            data() {
                return {
                    chartData: {
                        xData: ['渭滨区', '金台区', '陈仓区', '凤翔区'],
                        seriesData: [
                            { value: 2, name: '渭滨区' },
                            { value: 15, name: '金台区' },
                            { value: 5, name: '陈仓区' },
                            { value: 1, name: '凤翔区' },
                        ],
                    },
                    // 以下是dataV组件中数字翻牌器需要的数据
                    numberData: [
                        {
                            number: {
                                number: [1542],
                                toFixed: 0,
                                textAlign: 'left',
                                content: '{nt}',
                                style: {
                                    fontSize: 20,
                                },
                            },
                            text: '总量',
                        },
                        {
                            number: {
                                number: [1535],
                                toFixed: 0,
                                textAlign: 'left',
                                content: '{nt}',
                                style: {
                                    fontSize: 20,
                                },
                            },
                            text: '在线数量',
                        },
                        {
                            number: {
                                number: [7],
                                toFixed: 0,
                                textAlign: 'left',
                                content: '{nt}',
                                style: {
                                    fontSize: 20,
                                },
                            },
                            text: '断线数量',
                        },
                        {
                            number: {
                                number: [126],
                                toFixed: 0,
                                textAlign: 'left',
                                content: '{nt}',
                                style: {
                                    fontSize: 20,
                                },
                            },
                            text: '待安装数量',
                        },
                    ],
                }
            },
        }
    </script>
    <style lang="scss" scoped>
        $box-width: 245px;
        $box-height: 410px;
    
        .container {
            padding: 10px;
            height: $box-height;
            width: $box-width;
            border-radius: 10px;
    
            .bg-color-black {
                height: $box-height;
                border-radius: 10px;
            }
    
            .text {
                color: #c3cbde;
            }
    
            .bottom-data {
                .item-box {
                    & > div {
                        padding-right: 5px;
                    }
    
                    font-size: 14px;
                    float: right;
                    position: relative;
                    width: 50%;
                    color: #d3d6dd;
    
                    .dv-digital-flop {
                        width: 120px;
                        height: 30px;
                    }
    
                    // 金币
                    .coin {
                        position: relative;
                        top: 6px;
                        font-size: 20px;
                        color: #ffc107;
                    }
    
                    .colorYellow {
                        color: yellowgreen;
                    }
    
                    p {
                        text-align: center;
                    }
                }
            }
        }
    </style>
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值