最终效果如图
组件结构设计
外部 Hotpage.vue
<template>
<div class="comP1">
<Hot></Hot>
</div>
</template>
<script>
import Hot from "@/components/Hot";
export default {
name: "HotPage",
components:{Hot}
}
</script>
<style scoped>
</style>
内部 Rank.vue
三个span 是绝对定位 左右切换按钮 和当前数据的类目名
计算属性展示下方所用到的样式和文本 和把 vuex里的 theme 映射进来 computed:{ NowName(){ if (!this.allData){ return '' } return this.allData[this.currentIndex].name }, comStyle(){ return `font-size:${this.FontS}px;color:${getThemeValue(this.theme).titleColor}` }, ...mapState(['theme']) },
getThemeValue 工具函数:返回不同主题对应的合适内容
const theme = {
chalk:{
// 背景颜色
backgroundColor:'#161522',
// 标题的文字颜色
titleColor:'#ffffff',
// 左上角logo的图表路径
logoSrc:'logo_dark.png',
// 切换主题按钮的图片路径
themeSrc:'qiehuan_dark.png',
// 页面顶部的边框图片
herderBorderSrc:'header_border_dark.png'
},
vintage:{
// 背景颜色
backgroundColor:'#eee',
// 标题的文字颜色
titleColor:'#000000',
// 左上角logo的图表路径
logoSrc:'logo_light2.png',
// 切换主题按钮的图片路径
themeSrc:'qiehuan_light.png',
// 页面顶部的边框图片
herderBorderSrc:'header_border_light.png'
}
}
export function getThemeValue(themeName) {
return theme[themeName]
}
<!-- 显示商品销量占比的饼图 -->
<template>
<div class="comP2">
<div class="comP2" ref="hot_1"></div>
<span class="iconfont arr-left" @click="ALeft" :style="comStyle"></span>
<span class="iconfont arr-right" @click="ARight" :style="comStyle"></span>
<span class="cat-name" :style="comStyle">{{NowName}}</span>
</div>
</template>
<script>
export default {
data () {
return {}
},
methods: {}
}
</script>
<style lang="less" scoped>
</style>
初始化图表+数据的获取+更新图表
挂载的生命周期中 注册图表、发送请求获取数据、添加响应页面尺寸的事件
卸载的生命周期中 、解绑响应页面尺寸的事件
mounted() {
// 渲染DOM元素之后 初始化图表实例 请求数据 监听页面尺寸变化
this.initChart()
this.getData()
window.addEventListener('resize',this.screenAdapter)
this.screenAdapter()
},
destroyed() {
window.removeEventListener('resize',this.screenAdapter)
},
初始化图表
initChart(){
this.chartsInstance = this.$echarts.init(this.$refs.hot_1,this.theme)
const initOption = {
title:{
text:'▎ 热销商品占比',
left:20,
top:20
},
series:[
{
type:'pie',
label:{
show:false // 饼图二级数据默认不显示
},
emphasis:{
label:{
show:true // 在鼠标悬浮的时候 显示标题
},
labelLine:{
show:false // 饼图内部标题的提示线 不展示
}
}
}
]
}
this.chartsInstance.setOption(initOption)
},
获取数据 重新渲染图表
请求过来的数据内容:
[
{
"name": "2022一级建造师",
"children": [
{
"name": "建筑",
"value": 56202,
"children": [
{
"name": "建筑无忧全科",
"value": 10281
},
{
"name": "建筑无忧全科",
"value": 22331
},
{
"name": "建筑抖音特价班",
"value": 23590
}
]
},
{
"name": "市政",
"value": 42013,
"children": [
{
"name": "市政无忧全科",
"value": 7896
},
{
"name": "市政无忧全科",
"value": 10422
},
{
"name": "市政单独教材班",
"value": 23695
}
]
},
{
"name": "法规",
"value": 210282,
"children": [
{
"name": "法规名师班",
"value": 87330
},
{
"name": "法规押题班",
"value": 65770
},
{
"name": "法规基础班",
"value": 57182
}
]
},
{
"name": "管理",
"value": 168203,
"children": [
{
"name": "管理押题班",
"value": 68203
},
{
"name": "管理速成班",
"value": 50000
},
{
"name": "管理抢分班",
"value": 50000
}
]
},
{
"name": "经济",
"value": 40292,
"children": [
{
"name": "经济基础班",
"value": 292
},
{
"name": "经济领航班",
"value": 10000
},
{
"name": "经济突分班",
"value": 10000
}
]
},
{
"name": "机电",
"value": 20313,
"children": [
{
"name": "机电基础班",
"value": 5000
},
{
"name": "机电名师班",
"value": 15313
}
]
}
]
},
{
"name": "2023二级建造师",
"children": [
{
"name": "管理",
"value": 201023,
"children": [
{
"name": "管理速成班",
"value": 1023
},
{
"name": "管理单项突击班",
"value": 40000
},
{
"name": "管理无忧单项班",
"value": 160000
}
]
},
{
"name": "市政",
"value": 103735,
"children": [
{
"name": "市政尊享单科班",
"value": 3735
},
{
"name": "市政畅学突分班",
"value": 70000
},
{
"name": "市政押题班",
"value": 30000
}
]
},
{
"name": "法规",
"value": 83834,
"children": [
{
"name": "法规名师班",
"value": 3834
},
{
"name": "法规单科抢分班",
"value": 50000
},
{
"name": "法规尊享班",
"value": 30000
}
]
},
{
"name": "建筑",
"value": 68384,
"children": [
{
"name": "建筑案例特训班",
"value": 30000
},
{
"name": "建筑无忧班",
"value": 8384
},
{
"name": "建筑尊享班",
"value": 30000
}
]
},
{
"name": "机电",
"value": 45038,
"children": [
{
"name": "机电案例特训",
"value": 10000
},
{
"name": "机电真题解析",
"value": 5038
},
{
"name": "机电考前冲刺",
"value": 30000
}
]
},
{
"name": "公路",
"value": 90382,
"children": [
{
"name": "公路基础精讲",
"value": 382
},
{
"name": "公路考前押题",
"value": 60000
},
{
"name": "公路案例专项",
"value": 30000
}
]
},
{
"name": "水利",
"value": 10201,
"children": [
{
"name": "水利案例特训",
"value": 10000
},
{
"name": "水利考前抢分",
"value": 201
}
]
}
]
},
{
"name": "其他建工科目",
"children": [
{
"name": "一级造价工程师",
"value": 430291,
"children": [
{
"name": "一造基础班",
"value": 30291
},
{
"name": "一造无忧班",
"value": 100000
},
{
"name": "一造尊享班",
"value": 300000
}
]
},
{
"name": "监理工程师",
"value": 80284,
"children": [
{
"name": "监理基础班",
"value": 60284
},
{
"name": "监理畅学班",
"value": 10000
},
{
"name": "监理尊享班",
"value": 10000
}
]
},
{
"name": "安全工程师",
"value": 40294,
"children": [
{
"name": "安工尊享班",
"value": 10294
},
{
"name": "安工护航班",
"value": 5000
},
{
"name": "安工尊享班",
"value": 25000
}
]
},
{
"name": "二级造价工程师",
"value": 50939,
"children": [
{
"name": "二造抖音班",
"value": 10939
},
{
"name": "二造小红书",
"value": 10000
},
{
"name": "二造快手班",
"value": 30000
}
]
},
{
"name": "其他",
"value": 10921,
"children": [
{
"name": "岩土工程师",
"value": 921
},
{
"name": "建筑工程师",
"value": 10000
}
]
}
]
}
]
组件之前预留的data:
data(){ return{ chartsInstance:null, allData:null, FontS:null, currentIndex:0 // 就是显示请求过来数据(数组)的索引值 } },
getData(){
const {data:res} = await this.$http.get('hotproduct')
this.allData = res
this.updateChart()
},
updateChart(){
// 处理饼图需要的数据
const legendData = this.allData[this.currentIndex].children.map(item =>{
return item.name
})
const seriesData = this.allData[this.currentIndex].children.map(item =>{
return {
name:item.name,
value:item.value,
children:item.children // 增加三级分类数据 便于后面使用
}
})
const dataOption = {
legend:{
data:legendData,
top:'18%',
icon:'circle'
},
tooltip:{
show:true,
// 显示提示 可以用formatter 函数自定义
formatter:arg => {
const thirdCate = arg.data.children
let total = 0
thirdCate.forEach(item =>{
total += item.value
})
let retStr = ''
thirdCate.forEach(item =>{
// 三级分类的名称 所占百分比 换行
retStr += `${item.name} : ${parseInt(item.value / total * 100)+ '%'} <br>`
})
return retStr
// 循环计算出 所有三级菲
}
},
series:[
{
data:seriesData
}
]
}
this.chartsInstance.setOption(dataOption)
},
下一项 上一项 按钮的回调 更改 currentIndex(限制最大值最小值) 重新调用 updateChart更新图表
ALeft(){
this.currentIndex --
if (this.currentIndex < 0){
this.currentIndex = this.allData.length - 1
}
this.updateChart()
},
ARight(){
this.currentIndex ++
// console.log(this.currentIndex)
// console.log(this.allData)
if (this.currentIndex > this.allData.length - 1){
this.currentIndex = 0
}
this.updateChart()
}
响应屏幕尺寸的回调
screenAdapter(){
const titleFontSize = this.$refs.hot_1.offsetWidth / 100 * 3.6
this.FontS = titleFontSize
const adapterOption = {
title:{
textStyle: {
fontSize: titleFontSize
}
},
series:[
{
radius:titleFontSize * 4.5,
center:['50%','60%']
}
],
legend: {
itemWidth: titleFontSize /1.2,
itemHeight: titleFontSize /1.2,
itemGap: titleFontSize/2,
textStyle: {
fontSize: titleFontSize /1.2
}
}
}
this.chartsInstance.setOption(adapterOption)
this.chartsInstance.resize()
},