Vue 封装echarts饼状图(Pie)组件

目的:减少重复代码,便于维护

效果显示:

组件代码

javascript 复制代码
<template>
    <div class="ldw-data-content-box">
        <div class="ldw-chilren-box">
            <div class="title">
                <div>{{ title }}</div>
                <div class="btn">
                    <slot></slot>
                </div>
            </div>
            <div v-if="row" class="ldw-row-class">
                <div class="canvas-box">
                    <div :id="'canvas-box'+number" style="width: 100%;height:100%;"></div>
                </div>
                <div class="quan-quan-box" style="justify-content: space-evenly;">
                    <div class="ldw-quan-quan" style="width:100%;" v-for="(item,index) in data" :key="index">
                        <div class="ldw-quan-box" :style="{background:item.ldwColor.length?`linear-gradient(0deg,${item.ldwColor[0]},${item.ldwColor[1]})`:''}"></div>
                        <div class="ldw-text-text ldw-w" :style="'width:'+item.w+'px'">{{item.name}}</div>
                        <div>:</div>
                        <div>{{ item.value }}</div>
                    </div>
                </div>
            </div>
            <div style="width:100%;flex:1;display: flex;flex-flow: column;" v-else>
                <div style="width:100%;flex:1;">
                    <div :id="'canvas-box'+number" style="width: 100%;height:100%;"></div>
                </div>
                <div :style="{'height':h+'px','marginTop':top+'px','margin':'0 auto'}" :class="column?'flex-column':'flex-center-sp flex flex-center-cz flex-col'">
                    <div class="ldw-quan-quan" :class="column?'flex-center-sp':''" v-for="(item,index) in data" :key="index">
                        <div class="ldw-quan-box" :style="{background:item.ldwColor.length?`linear-gradient(0deg,${item.ldwColor[0]},${item.ldwColor[1]})`:''}"></div>
                        <div v-if="column">{{item.name}}</div>
                        <div v-else class="ldw-text-text ldw-w" :style="'width:'+item.w+'px'">{{item.name}}</div>
                        <div>:</div>
                        <div>{{ item.value }}</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
var echarts = require("echarts");
const total = function(data){
    return data.reduce((prev,cur)=>{
        return prev+cur.value
    },0)
}
export default {
    props:{
        title:"",
        data:{
            require:true,
            type:Array,
            default:()=>[]
        },
        w:{
            type:String,
            default:"auto"
        },
        column:{
            type:Boolean,
            default:true
        },
        row:{
            type:Boolean,
            default:false
        },
        listH:{
            type:Number,
            default:56
        },
        label:{
            type:Boolean,
            default:false
        }
    },
    data(){
        return{
            bg:["#0090FF","#31CFB8","#E55240"],
            number:null,
            top:0,
            h:56,
            myChart:null
        }
    },
    watch: {
        data: {
            //深度监听,可监听到对象、数组的变化
            handler(val, oldVal) {
                if (val != null) {
                    this.setOption();
                }
                
            },
            deep: true, //true 深度监听
        },
        listH:{
            //深度监听,可监听到对象、数组的变化
            handler(val, oldVal) {
                this.h  = val
            },
        }
    },
    created(){
        this.h = this.listH
        this.number = Math.random(1000)+1;
    },
    mounted(){
        this.initData()
    },
    methods:{
        initData(){
            let canvas = document.getElementById(`canvas-box${this.number}`)
            this.myChart = echarts.init(canvas);
            this.setClick()
            this.setOption()
        },
        setClick(){
            let that = this
            this.myChart.on("click", function(params) {
                that.$emit('eClick',params)
            });
        },
        setOption(){
            let option = {
                title: {
                    text:'总计',//主标题文本
                    subtext:""+total(this.data),//副标题文本
                    left:'center',
                    top:'40%',
                    textStyle:{
                        fontSize: 16,
                        color:'#6c7a89',
                        align:'center'
                    },
                    subtextStyle:{
                        fontFamily : "微软雅黑",
                        fontSize: 26,
                        color:'#060606',
                        fontWeight:600
                    }
                },
                tooltip: {
                    trigger: 'item'
                },
                legend: {
                    show:false
                },
                series: [
                    {
                        name:this.title,
                        type: 'pie',
                        radius: ['55%', '80%'],
                        avoidLabelOverlap: false,
                        label: this.labelFn(this.label),
                        labelLine: this.labelLineFn(this.label),
                        data: this.colorFormat(this.data)
                    }
                ]
            };

            this.myChart.setOption(option)
        },
        resize(){
            this.myChart.resize()
        },
        labelColor(){
            arr.forEach((item)=>{
                if(item.ldwColor){
                    item.itemStyle = {
                        color:{
                        }
                    }
                }
            })
            return arr
        },
        colorFormat(arr){
            arr.forEach((item)=>{
                if(item.ldwColor){
                    item.itemStyle = {
                        color:{
                            type: 'linear',
                            x: 0,
                            y: 0,
                            x2: 0,
                            y2: 1,
                            colorStops: [{
                                offset: 0, color: item.ldwColor[0] // 0% 处的颜色
                            }, {
                                offset: 1, color: item.ldwColor[1] // 100% 处的颜色
                            }],
                            global: false // 缺省为 false
                        }
                    }
                }
            })
            return arr
        },
        labelFn(state){
            if(state){
                return {
                    color: 'inherit',
                    fontWeight:"bold",
                    fontSize:12,
                    padding:[0,-60],
                    formatter:(params)=>{
                        return `${params.name}\n${(params.value/total(this.data)*100).toFixed(1)}%\n\n`
                    }
                }
            }else{
                return {
                    show:false
                }
            }
        },
        labelLineFn(state){
            if(state){
                return {
                    smooth: 0.2,
                    length: 10,
                    length2: 70
                }
            }else{
                return {
                    show:false
                }
            }
        }
    }
}
</script>

<style scoped>
.ldw-data-content-box{
    width:100%;
    height:100%;
    display: flex;
}

.ldw-data-content-box>.ldw-chilren-box{
    width:100%;
    height:100%;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-flow: column;
    overflow: hidden;
}
.ldw-data-content-box>.ldw-chilren-box>.title{
    font-size: 18px;
    color:#000;
    text-align: center;
    padding:24px 0;
    width:100%;
    position: relative;
}

.ldw-bg-box{
    background: rgba(255,255,255,0.5);
    border: 1px solid #F4FDFE;
    border-radius: 20px;
}

.ldw-text-text{
	display: inline-block;
	text-align: justify;
	line-height: 0;
	margin-left: 20px;
}

.ldw-text-text::after{
	content:"";
	display: inline-block;
	width:100%;
	overflow:hidden;
	height:0;
}

.ldw-quan-quan{
    width:100%;
    display: flex;
    align-items: center;
}

.ldw-w{
    margin-top:6px;
    position: relative;
}

.ldw-quan-box{
    width: 13px;
    height: 13px;
    border-radius: 2px;
    margin-right: 20px;
}

.flex-column{
    width:100%;
    display: flex;
    justify-content: space-around;
}

.flex-column .ldw-w{
    width: auto;
}

.flex-column .ldw-quan-box{
    margin-right: 10px;
}

.btn{
    position: absolute;
    right: 50px;
    top:50%;
    transform: translateY(-50%);
}

.ldw-row-class{
    display: flex;
    width: 100%;
    justify-content: center;
    align-items: center;
    flex: 1;
    padding:0 20px;
}

.canvas-box{
    text-align: center;
    width:65%;
    height: 100%;
}

.quan-quan-box{
    width:35%;
    height: 100%;
    display: flex;
    flex-flow: column;
    justify-content: center;
    align-items: center;
}

.m-m-m{
    margin: 0 auto;
}
</style>

调用代码

javascript 复制代码
<template>
    <div class="root flex flex-col border-box">
        <div  style="width: 400px; height: 400px;"  >
            <Pie  :title="'统计'"  :data="list" ></Pie>
        </div>
    </div>
</template>

<script>
    import Pie from '@/components/echarts/pieInfo.vue'

    export default{
        name:'',
        created() {
        },
        mounted() {
            this.list = this.chartData
        },
        components: {Pie},
        data() {
            return {
                list:[],
                chartData:
                [
                    {value:100, type:'一季度'},
                    {value:105, type:'二季度'},
                    {value:201, type:'三季度'},
                    {value:167, type:'四季度'},
                ]
            }
        },
        methods:{
        }
    }
</script>
相关推荐
成都被卷死的程序员33 分钟前
响应式网页设计--html
前端·html
mon_star°1 小时前
将答题成绩排行榜数据通过前端生成excel的方式实现导出下载功能
前端·excel
Zrf21913184551 小时前
前端笔试中oj算法题的解法模版
前端·readline·oj算法
文军的烹饪实验室2 小时前
ValueError: Circular reference detected
开发语言·前端·javascript
Martin -Tang3 小时前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发3 小时前
解锁微前端的优秀库
前端
王解4 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
我不当帕鲁谁当帕鲁4 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂4 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐5 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架