Skip to content

黑马就业数据平台(后端接口)(四) ​

本页对应 黑马就业数据平台(后端接口),共 7 段视频,约 44 分钟。

学习目标 ​

  • 能根据组别数据结构,修改 ECharts 柱状图 X 轴类目与 series 中期望薪资、实际薪资数据,并配置 itemStyle 线性渐变色。
  • 能通过事件委托为组别按钮绑定点击事件,实现按钮排他高亮,并按点击组号切换 X 轴与 series 数据后重新调用 setOption 渲染。
  • 能将男女薪资分布双饼图示例整合到项目中,抽取渲染函数、传入薪资数据,并完成 ECharts 实例初始化与 option 配置。
  • 能设置双饼图的 radius 与 center,完成两个饼图的大小、位置布局,并配置 title 数组实现主标题、男生、女生标题及文字样式。
  • 能完成男女薪资分布图表的数据映射、颜色、tooltip 配置,移除不需要的 roseType、borderRadius 等属性并验证最终渲染效果。
  • 能使用 git status、git add、git commit、git push 完成本地提交与远程仓库推送,并验证远程分支更新结果。

知识点 ​

需求与目标 ​

这一节要完成数据看板中的“每组薪资”图表:默认展示第一组组员的“期望薪资”和“实际薪资”两组柱状图,点击上方组号按钮后,切换高亮状态,并重新渲染对应组别的数据。

先明确效果,再去找实现方式。需求图如下:

每组薪资图表需求效果图

为什么需要先看需求图?因为这里不只是画一个柱状图,还要处理组别切换、按钮高亮、坐标轴文字颜色、虚线轴线、柱状图渐变色等细节。先拆成“图表渲染”和“点击切换”两部分,后面就不容易乱。

找示例并抽取配置项 ​

怎么想:ECharts 图表优先去官方示例里找相似结构。这里需要的是柱状图,找到示例后不要整段照搬,而是保留核心 option,再按项目需要调整。

需要先调整的公共设置包括:显示提示框、轴线样式、分割线样式。

javascript
const option = {
  tooltip: {},// 显示提示框
  xAxis: {
    axisLine: {// 轴线样式
      lineStyle: {
        color: '',
        type: ''
      }
    }
  },
  yAxis: {
    splitLine: {// 分割线样式
      lineStyle: {
        type: ''
      }
    }
  }
}

怎么做:把示例整合到项目后,封装成 renderGroupSalary(groupData),在首页数据请求完成后调用。这样图表逻辑和接口请求分开,后续维护更清晰。

整合项目并默认渲染第一组 ​

为什么需要先默认渲染?因为页面打开时不能等用户点击后才出现图表,必须先展示一组数据。

转写稿里反复确认了数据结构:groupData 是一个对象,键是组号,例如 1、2、3,每个键对应一个数组。数组每一项里有 name、hope_salary、salary。所以默认取 groupData[1]:

javascript
xAxis: {
  type: 'category',
  data: groupData[1].map(v => v.name),
  axisLine: {
    lineStyle: {
      color: '#ccc',
      type: 'dashed'
    }
  },
  axisLabel: {
    color: '#999'
  }
}

这里要注意:axisLabel.color 要单独设置,否则文字颜色会默认跟随轴线颜色。yAxis.splitLine.lineStyle.type 设为 dashed,让分割线变成虚线。

调整 grid 与柱状图渐变配色 ​

为什么先调 grid?因为坐标轴文字、图例和绘图区容易挤在一起。通过 left/top/right/bottom 给图表留出空间:

javascript
grid: {
  left: 70,
  top: 30,
  right: 30,
  bottom: 50
}

接着处理 series。笔记强调:提供了标准色,就用标准色。左侧“期望薪资”用绿色渐变,右侧“实际薪资”用蓝色渐变。渐变方向是竖向,所以设置 x:0, y:0, x2:0, y2:1。

javascript
series: [
  {
    name: '期望薪资',
    data: groupData[1].map(v => v.hope_salary),
    type: 'bar',
    itemStyle: {
      color: {
        type: 'linear',
        x: 0,
        y: 0,
        x2: 0,
        y2: 1,
        colorStops: [{
          offset: 0, color: '#34D39A'
        }, {
          offset: 1, color: 'rgba(52,211,154,0.2)'
        }],
        global: false
      }
    }
  },
  {
    name: '实际薪资',
    data: groupData[1].map(v => v.salary),
    type: 'bar',
    itemStyle: {
      color: {
        type: 'linear',
        x: 0,
        y: 0,
        x2: 0,
        y2: 1,
        colorStops: [{
          offset: 0, color: '#499FEE'
        }, {
          offset: 1, color: 'rgba(73,159,238,0.2)'
        }],
        global: false
      }
    }
  }
]

易错点:不要把渐变写成横向;不要漏掉 global: false;颜色值不要自己另配一套,既然设计给了标准色,就直接使用。

点击切换高亮与数据 ​

为什么切换逻辑要写在 renderGroupSalary 内部?因为点击后要访问 myChart 和 option,写在外面拿不到这两个变量。转写稿里也特别提醒:切换数据要放在这个函数里面。

思路分三步:先做按钮高亮排他,再根据按钮文字拿到组号,最后修改 option 并调用 setOption 重新渲染。

javascript
const btns = document.querySelector('#btns')
btns.addEventListener('click', (e) => {
  if (e.target.classList.contains('btn')) {
    btns.querySelector('.btn-blue').classList.remove('btn-blue')
    e.target.classList.add('btn-blue')

    const index = e.target.innerText
    const data = groupData[index]

    option.xAxis.data = data.map(v => v.name)
    option.series[0].data = data.map(v => v.hope_salary)
    option.series[1].data = data.map(v => v.salary)

    myChart.setOption(option)
  }
})

这里用事件委托绑定到 #btns,避免给每个按钮循环绑定。e.target.innerText 正好是组号,可以直接作为 groupData 的键。修改完 option 后必须再次调用 setOption,否则数据不会刷新。

易错点:排他时先移除旧的 .btn-blue 再给当前按钮添加;判断点击目标是否包含 btn;切换后三个数据都要更新:xAxis.data、series[0].data、series[1].data。

关键代码整合 ​

完整渲染函数可以按下面结构组织,注意 myChart、option 和点击事件都放在函数内部:

javascript
function renderGroupSalary(groupData) {
  const dom = document.querySelector('#lines')
  const myChart = echarts.init(dom)

  const option = {
    tooltip: {},
    grid: {
      left: 70,
      top: 30,
      right: 30,
      bottom: 50
    },
    xAxis: {
      type: 'category',
      data: groupData[1].map(v => v.name),
      axisLine: {
        lineStyle: {
          color: '#ccc',
          type: 'dashed'
        }
      },
      axisLabel: {
        color: '#999'
      }
    },
    yAxis: {
      type: 'value',
      splitLine: {
        lineStyle: {
          type: 'dashed'
        }
      }
    },
    series: [
      {
        name: '期望薪资',
        data: groupData[1].map(v => v.hope_salary),
        type: 'bar',
        itemStyle: {
          color: {
            type: 'linear',
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              { offset: 0, color: '#34D39A' },
              { offset: 1, color: 'rgba(52,211,154,0.2)' }
            ],
            global: false
          }
        }
      },
      {
        name: '实际薪资',
        data: groupData[1].map(v => v.salary),
        type: 'bar',
        itemStyle: {
          color: {
            type: 'linear',
            x: 0,
            y: 0,
            x2: 0,
            y2: 1,
            colorStops: [
              { offset: 0, color: '#499FEE' },
              { offset: 1, color: 'rgba(73,159,238,0.2)' }
            ],
            global: false
          }
        }
      }
    ]
  }

  myChart.setOption(option)

  const btns = document.querySelector('#btns')
  btns.addEventListener('click', (e) => {
    if (e.target.classList.contains('btn')) {
      btns.querySelector('.btn-blue').classList.remove('btn-blue')
      e.target.classList.add('btn-blue')

      const index = e.target.innerText
      const data = groupData[index]

      option.xAxis.data = data.map(v => v.name)
      option.series[0].data = data.map(v => v.hope_salary)
      option.series[1].data = data.map(v => v.salary)

      myChart.setOption(option)
    }
  })
}

最后在首页请求数据后调用:

javascript
const { overview, year, salaryData, groupData, provinceData } = res.data
renderOverview(overview)
renderYearSalary(year)
renderSalary(salaryData)
renderGroupSalary(groupData)

提交记录 ​

功能完成后做一次提交:

bash
git add .
git commit -m"数据看板-每组薪资"

本节的核心不是“画出一个柱状图”,而是掌握 ECharts 的配置复用:先找示例,再按数据结构替换 xAxis.data 和 series.data,最后通过修改同一个 option 并调用 setOption 完成交互切换。

需求与整体思路 ​

男女薪资分布需求图

本节要在数据看板中完成“男女薪资分布”图表:上下两个饼图,上方男生、下方女生,左侧一个大标题,两个饼图中间分别写“男生”“女生”。

  • 为什么需要:班级薪资分布是把男女生数量合在一起看,这里要把 b_count 和 g_count 拆开,分别展示男女生的薪资区间分布。
  • 怎么想:它和刚做过的班级薪资分布很像,仍然走“找示例 → 整合到项目 → 调整设置”的流程。示例可去 ECharts 示例 找饼图,选一个相近的“南丁格尔玫瑰图”,复制成两个 series。
  • 怎么做:先去掉不需要的 toolbox、legend,保留 series,再封装 renderGenderSalary(salaryData),初始化 #gender 容器并 setOption(option)。
  • 易错点:不要忘记把函数放到 getData 中调用并传入 salaryData;两个饼图初始位置会重叠,后面必须分别调 center。

先调饼图大小和位置 ​

  • 为什么需要:刚整合时两个饼图叠在一起,几乎看不清,所以先调 series 的 radius 和 center。
  • 怎么想:radius 控制内外半径,center 控制圆心位置;上方图放在 ['50%','30%'],下方图放在 ['50%','70%']。
  • 怎么做:按笔记给出的位置直接设置:
javascript
const option = {
  series: [
    {
      radius: ['20%', '30%'],
      center: ['50%', '30%'],
      data: []
    },
    {
      radius: ['20%', '30%'],
      center: ['50%', '70%'],
      data: []
    },
  ]
}
  • 易错点:radius、center 里是百分比字符串;两个 series 都要改,只改一个仍会重叠。

用数组设置多个标题 ​

  • 为什么需要:这个图有三个标题:主标题“男女薪资分布”、上方“男生”、下方“女生”。普通对象只能写一个标题,所以要用数组。
  • 怎么想:title 写成数组,数组里每个对象就是一个标题的内容和位置。
  • 怎么做:
javascript
const option = {
  title: [
    {
      left: 10,
      top: 10,
      textStyle: {
        fontSize: 16
      }
    },
    {
      left: '50%',
      top: '45%',
      textStyle: {
        fontSize: 12
      }
    },
    {
      left: '50%',
      top: '85%',
      textStyle: {
        fontSize: 12
      }
    }
  ],
}
  • 易错点:title 不是对象而是数组;文字样式写在 textStyle 里;两个小标题加 textAlign: 'center' 才能水平居中。

绑定数据、颜色与提示 ​

  • 为什么需要:两个饼图要分别显示男生、女生的薪资区间数据,并且去掉玫瑰图不需要的样式。
  • 怎么想:第一个 series 用 salaryData.map 取 b_count,第二个取 g_count,每项返回 { value, name }。
  • 怎么做:男生数据写成 data: salaryData.map(v => ({ value: v.b_count, name: v.label })),女生把 b_count 换成 g_count;去掉 roseType 和 itemStyle.borderRadius;加 tooltip: { trigger: 'item' };颜色用 color: ['#fda224', '#5097ff', '#3abcfa', '#34d39a']。
  • 易错点:不要把男女字段写反;保留 roseType 会让扇区大小随数据变化;tooltip 不加,鼠标放上去没有提示。

调用、提交与关键代码 ​

在 getData 中解构出 salaryData 后调用 renderGenderSalary(salaryData)。完成后提交:

bash
git add .
git commit -m"数据看板-男女薪资分布"

关键代码如下:

javascript
// 渲染男女薪资分布函数
function renderGenderSalary(salaryData) {
  // 初始化实例
  const dom = document.querySelector('#gender')
  const myChart = echarts.init(dom)

  const option = {
    tooltip: {
      trigger: 'item'
    },
    color: ['#fda224', '#5097ff', '#3abcfa', '#34d39a'],
    title: [
      {
        text: '男女薪资分布',
        left: 10,
        top: 10,
        textStyle: {
          fontSize: 16
        }
      },
      {
        text: '男生',
        left: '50%',
        top: '45%',
        textStyle: {
          fontSize: 12
        },
        textAlign: 'center'
      },
      {
        text: '女生',
        left: '50%',
        top: '85%',
        textStyle: {
          fontSize: 12
        },
        textAlign: 'center'
      }
    ],
    series: [
      {
        type: 'pie',
        radius: ['20%', '30%'],
        center: ['50%', '30%'],
        data: salaryData.map(v => {
          return { value: v.b_count, name: v.label }
        })
      },
      {
        type: 'pie',
        radius: ['20%', '30%'],
        center: ['50%', '70%'],
        data: salaryData.map(v => {
          return { value: v.g_count, name: v.label }
        })
      }
    ]
  }

  myChart.setOption(option)
}

易错点:函数名、容器 #gender、salaryData 参数三处要一致;两个 series 的数据字段要分别对应 b_count 和 g_count。

课件图示 ​

课件第25页:核心步骤: 数据看板-男女薪资分布 整合到项目 找示例 调整设置 color:颜

课件第26页:核心步骤: 数据看板-男女薪资分布 整合到项目 找示例 调整设置 抽取函数 调用

课件第27页:核心步骤: 数据看板-男女薪资分布 整合到项目 找示例 调整设置 title:标

课件第28页:核心步骤: 数据看板-男女薪资分布 整合到项目 找示例 调整设置 series:

课件第19页:核心步骤: 数据看板-每组薪资 整合到项目 找示例 调整设置 切换效果

课件第20页:核心步骤: 数据看板-每组薪资 整合到项目 找示例 调整设置 切换效果 cons

课件第21页:核心步骤: 数据看板-每组薪资 整合到项目 找示例 调整设置 抽取函数 调用并传

课件第22页:核心步骤: 数据看板-每组薪资 整合到项目 找示例 调整设置 切换效果 xAxi

代码示例 ​

1. 每组薪资(柱状图 + 组别切换) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>每组薪资</title>
  <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
  <style>
    .dashboard { width: 640px; margin: 20px auto; font-family: sans-serif; }
    #lines { width: 640px; height: 360px; }
    #btns { display: flex; gap: 8px; margin-top: 10px; }
    .btn {
      width: 40px; height: 28px; cursor: pointer;
      border: 1px solid #ccc; background: #fff; border-radius: 4px;
    }
    /* 高亮样式类,切换时只做类名的增删 */
    .btn-blue { background: #499fee; border-color: #499fee; color: #fff; }
  </style>
</head>
<body>
  <div class="dashboard">
    <div id="lines"></div>
    <div id="btns">
      <button class="btn btn-blue">1</button>
      <button class="btn">2</button>
      <button class="btn">3</button>
      <button class="btn">4</button>
    </div>
  </div>

  <script>
    // 模拟后端返回的 groupData:键是组号,值是该组成员的薪资数组
    const groupData = {
      1: [
        { name: '工刚', hope_salary: 12000, salary: 10000 },
        { name: '龚军', hope_salary: 16000, salary: 13000 },
        { name: '张伟', hope_salary: 9000,  salary: 8000  },
        { name: '李娜', hope_salary: 18000, salary: 15000 },
        { name: '王强', hope_salary: 14000, salary: 12000 }
      ],
      2: [
        { name: '吕阳', hope_salary: 20000, salary: 18000 },
        { name: '薛秀英', hope_salary: 13000, salary: 11000 },
        { name: '刘洋', hope_salary: 15000, salary: 14000 },
        { name: '陈静', hope_salary: 17000, salary: 16000 },
        { name: '赵磊', hope_salary: 11000, salary: 9000 }
      ],
      3: [
        { name: '孙悦', hope_salary: 15000, salary: 13000 },
        { name: '周杰', hope_salary: 22000, salary: 20000 },
        { name: '吴敏', hope_salary: 10000, salary: 9000  },
        { name: '郑爽', hope_salary: 19000, salary: 17000 },
        { name: '冯超', hope_salary: 12500, salary: 11000 }
      ],
      4: [
        { name: '蒋雯', hope_salary: 21000, salary: 19000 },
        { name: '沈括', hope_salary: 14000, salary: 12000 },
        { name: '韩梅', hope_salary: 16000, salary: 15000 },
        { name: '曹阳', hope_salary: 11000, salary: 10000 },
        { name: '许诺', hope_salary: 17500, salary: 16000 }
      ]
    }

    // 渲染每组薪资
    function renderGroupSalary(groupData) {
      // 初始化实例(必须在函数内部初始化,后面的事件回调才拿得到 myChart)
      const dom = document.querySelector('#lines')
      const myChart = echarts.init(dom)

      // 定义选项和数据
      const option = {
        // 显示提示框
        tooltip: {},
        // 绘图网格
        grid: {
          left: 70,
          top: 30,
          right: 30,
          bottom: 50
        },
        xAxis: {
          type: 'category',
          // 默认渲染第一组的数据
          data: groupData[1].map(v => v.name),
          // 线的类型、颜色
          axisLine: {
            lineStyle: {
              color: '#ccc',
              type: 'dashed'
            }
          },
          // 刻度标签文字颜色
          axisLabel: {
            color: '#999'
          }
        },
        yAxis: {
          type: 'value',
          // 分割线类型
          splitLine: {
            lineStyle: {
              type: 'dashed'
            }
          }
        },
        // series 中放多个对象,就渲染多个图形
        series: [
          {
            name: '期望薪资',
            data: groupData[1].map(v => v.hope_salary),
            type: 'bar',
            itemStyle: {
              // 柱状图的渐变色
              color: {
                type: 'linear',
                x: 0, y: 0, x2: 0, y2: 1,
                colorStops: [
                  { offset: 0, color: '#34D39A' },              // 0% 处的颜色
                  { offset: 1, color: 'rgba(52,211,154,0.2)' } // 100% 处的颜色
                ],
                global: false
              }
            }
          },
          {
            name: '实际薪资',
            data: groupData[1].map(v => v.salary),
            type: 'bar',
            itemStyle: {
              color: {
                type: 'linear',
                x: 0, y: 0, x2: 0, y2: 1,
                colorStops: [
                  { offset: 0, color: '#499FEE' },
                  { offset: 1, color: 'rgba(73,159,238,0.2)' }
                ],
                global: false
              }
            }
          }
        ]
      }

      // 基于选项和数据绘制图表
      myChart.setOption(option)

      // 切换效果:事件委托到父容器
      const btns = document.querySelector('#btns')
      btns.addEventListener('click', (e) => {
        if (e.target.classList.contains('btn')) {
          // 1. 排他:先取消上一个高亮,再高亮当前
          btns.querySelector('.btn-blue').classList.remove('btn-blue')
          e.target.classList.add('btn-blue')

          // 2. 拿到点击的组号(按钮文字就是 groupData 的键)
          const index = e.target.innerText
          const data = groupData[index]

          // 3. 修改同一个 option 的数据
          option.xAxis.data = data.map(v => v.name)
          option.series[0].data = data.map(v => v.hope_salary)
          option.series[1].data = data.map(v => v.salary)

          // 4. 重新渲染
          myChart.setOption(option)
        }
      })
    }

    renderGroupSalary(groupData)
  </script>
</body>
</html>

要点解释

  • myChart 必须在 renderGroupSalary 函数内部初始化:写在函数外面,点击事件回调里就拿不到实例,无法 setOption。
  • 切换只改 option 的三个地方:xAxis.data、series[0].data、series[1].data,然后再次 myChart.setOption(option),ECharts 会合并并重绘。
  • 高亮用「排他思想」:btns.querySelector('.btn-blue').classList.remove('btn-blue') 先取消旧的,再给当前按钮 classList.add('btn-blue');用事件委托绑在 #btns 上,避免给每个按钮循环绑定。
  • 易错点:groupData 的键是 1/2/3...,而 e.target.innerText 是字符串,对象取值时会自动转成字符串键,所以能对上;但不要写成 groupData[e.target]。
  • 易错点:渐变色的 x2:0, y2:1 表示从上到下(Y 轴方向)的线性渐变,写成 x2:1 就变成横向渐变了。

2. 男女薪资分布(双饼图 + 多标题) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>男女薪资分布</title>
  <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
  <style>
    #gender { width: 640px; height: 420px; margin: 20px auto; }
  </style>
</head>
<body>
  <div id="gender"></div>

  <script>
    // 模拟后端返回的 salaryData
    const salaryData = [
      { label: '1万以下', b_count: 12, g_count: 18 },
      { label: '1万-2万', b_count: 32, g_count: 28 },
      { label: '2万以上', b_count: 9,  g_count: 6  }
    ]

    // 渲染男女薪资分布
    function renderGenderSalary(salaryData) {
      // 初始化实例
      const dom = document.querySelector('#gender')
      const myChart = echarts.init(dom)

      const option = {
        // 提示框
        tooltip: {
          trigger: 'item'
        },
        // 不写 legend 就不会显示图例组件
        // 调色盘
        color: ['#fda224', '#5097ff', '#3abcfa', '#34d39a'],
        // 标题用数组,可以设置多个
        title: [
          {
            text: '男女薪资分布',
            left: 10,
            top: 10,
            textStyle: { fontSize: 16 }
          },
          {
            text: '男生',
            left: '50%',
            top: '45%',
            textStyle: { fontSize: 12 },
            textAlign: 'center'
          },
          {
            text: '女生',
            left: '50%',
            top: '85%',
            textStyle: { fontSize: 12 },
            textAlign: 'center'
          }
        ],
        series: [
          {
            type: 'pie',
            radius: ['20%', '30%'],
            // 圆心坐标:第一项横坐标,第二项纵坐标
            center: ['50%', '30%'],
            data: salaryData.map(v => ({
              value: v.b_count,
              name: v.label
            }))
          },
          {
            type: 'pie',
            radius: ['20%', '30%'],
            center: ['50%', '70%'],
            data: salaryData.map(v => ({
              value: v.g_count,
              name: v.label
            }))
          }
        ]
      }

      myChart.setOption(option)
    }

    renderGenderSalary(salaryData)
  </script>
</body>
</html>

要点解释

  • title 写成数组,数组里每个对象就是一个标题(主标题 + 两个副标题),位置用 left/top 百分比配合 textAlign: 'center' 让文字相对圆心居中。
  • 两个饼图靠 center 区分位置:['50%','30%'] 在上、['50%','70%'] 在下;radius: ['20%','30%'] 是内外半径,写成百分比才不会挤在一起。
  • 数据用 map 映射成 { value, name }:上图用 b_count(男生),下图用 g_count(女生);name 取 v.label 作为提示框文字。
  • 易错点:原示例里的 roseType: 'radius'(南丁格尔玫瑰图)会让扇区大小随数据变化,数据差异大时图形一大一小,本需求要删掉;itemStyle.borderRadius 圆角也要删掉。
  • 易错点:不写 legend 配置项图例就不会显示;tooltip 的 trigger: 'item' 才会在饼图扇区上出提示。
  • 易错点:map 回调里 return { value: ..., name: ... } 用箭头函数直接返回对象时,必须用小括号把对象包起来,否则会被当成函数体。

3. 整合到项目:统一取数后依次渲染 ​

javascript
// index.js —— 与上面两个渲染函数放在同一个文件中即可运行
// 首页-统计数据
async function getData() {
  // 真实项目写法(axios 拦截器已处理过响应):
  // const res = await axios({ url: '/dashboard' })

  // 这里用 mock 模拟接口返回,方便本地跑通
  const res = await mockDashboard()

  // 通过解构语法简化数据取值
  const { overview, year, salaryData, groupData, provinceData } = res.data

  // 调用函数-渲染顶部数据
  // renderOverview(overview)
  // 调用函数-渲染薪资走势
  // renderYearSalary(year)
  // 调用函数-渲染薪资分布
  // renderSalary(salaryData)

  // 调用函数-渲染每组薪资
  renderGroupSalary(groupData)
  // 调用函数-渲染男女薪资分布
  renderGenderSalary(salaryData)
}

// 模拟接口
function mockDashboard() {
  return Promise.resolve({
    data: {
      overview: {},
      year: [],
      salaryData: [
        { label: '1万以下', b_count: 12, g_count: 18 },
        { label: '1万-2万', b_count: 32, g_count: 28 },
        { label: '2万以上', b_count: 9,  g_count: 6  }
      ],
      groupData: {
        1: [{ name: '工刚', hope_salary: 12000, salary: 10000 }],
        2: [{ name: '吕阳', hope_salary: 20000, salary: 18000 }]
      },
      provinceData: []
    }
  })
}

getData()

要点解释

  • 数据只在 getData 里取一次,res.data 解构后把 groupData、salaryData 分别传给两个渲染函数,渲染函数只负责「拿数据 → 拼 option → setOption」。
  • 易错点:解构要写在 res.data 上(const { overview, ... } = res.data),写成 const { ... } = res 会拿到 undefined。
  • 易错点:renderGroupSalary 内部用 groupData[1] 做默认渲染,所以接口必须返回带 1 号键的数据,否则首次渲染就报错。
  • 整合完成后提交:git add . → git commit -m"数据看板-男女薪资分布" → git push。

常见错误 ​

  1. 现象: 点击组别后只有按钮高亮变化,图表数据不变。
    原因: 只改了按钮样式,未同步修改 option.xAxis.data 和两个 series.data,或修改后未再次 setOption。
    修法: 在点击处理中取当前组数据,依次更新 X 轴、期望薪资、实际薪资,最后调用 myChart.setOption(option)。

  2. 现象: 切换几次后出现多个按钮同时高亮。
    原因: 只给当前按钮加高亮类,未先清除旧高亮;或选择器范围过大误删/误加。
    修法: 先移除当前高亮类,再给 e.target 添加;在按钮容器内查找旧高亮,避免全局误操作。

  3. 现象: 点击按钮无反应,或拿到组号后图表报错/空白。
    原因: 未判断点击目标是否为按钮;用 innerText 取值时带空格;组号与 groupData 的键不一致。
    修法: 事件委托中先判断 classList.contains('btn'),用 textContent.trim() 取组号,并确认 groupData 的键为 1–8。

  4. 现象: 男女薪资两个饼图重叠,或一个饼图过大遮住另一个。
    原因: 两个 series 的 center、radius 未分别设置,仍沿用示例默认值。
    修法: 分别设置上下两个饼图的 center 和 radius,先固定骨架再填数据,最后浏览器验收是否重叠。

  5. 现象: 男女薪资饼图数据错位,男生图显示女生数据,或提示名称全是示例名。
    原因: data 未映射为 { value, name },或 b_count / g_count 用反。
    修法: 男生图映射 b_count,女生图映射 g_count,name 统一取 label,并在 tooltip 中核对。

  6. 现象: 饼图扇形大小随数据剧烈变化,或出现不需要的圆角/图例。
    原因: 保留了示例中的 roseType、itemStyle.borderRadius、legend 等配置。
    修法: 删除不需要的 roseType、圆角和图例配置;只保留需求要求的标题、调色盘、tooltip 和 series。

  7. 现象: 标题只显示一个,或三个标题位置错乱。
    原因: title 写成对象而非数组;多个标题未分别设置 left、top、textStyle、textAlign。
    修法: 用数组组织三个标题,分别设置主标题、男生、女生的位置和字号,并居中验收。

  8. 现象: 本地已提交,但远程仓库看不到最新代码。
    原因: 只执行了 git add / git commit,未执行推送。
    修法: 用 git status、git log 检查本地状态,再执行 git push,最后到远程分支确认提交记录。

练习 ​

  1. 完成“每组薪资”切换:点击 1–8 按钮时高亮排他,X 轴姓名、期望薪资、实际薪资同步切换;验收连续切换 3 组以上不串数据。
  2. 给每组薪资柱状图补上 tooltip,并将 X 轴线、Y 轴分割线调整为虚线;鼠标悬浮时能显示对应姓名和薪资。
  3. 实现男女薪资双饼图:两个饼图上下分布、不重叠,隐藏图例,使用给定调色盘,并补齐男生/女生标题。
  4. 将 salaryData 正确映射到上下两个饼图:男生用 b_count,女生用 g_count,名称用 label;删除 roseType 和多余圆角后对比扇形大小。
  5. 完成一次交付:提交本次看板代码并推送到远程分支,检查 git status、git log、git remote -v 和远程提交记录。

原视频对照 ​

#视频时长
1案例-每组薪资-数据处理07:24
2案例-每组薪资-切换组别12:42
3案例-男女薪资分布-整合图例07:33
4案例-男女薪资分布饼图大小位置设置03:18
5案例-男女薪资分布-标题设置05:00
6案例-男女薪资分布完成05:00
7上传远程仓库03:30

小结 ​

  1. 多图联动优先复用同一个 ECharts 实例和 option,切换时只改数据再 setOption,不要重复初始化。
  2. 组别按钮适合用事件委托处理,排他高亮、取组号、切数据应放在同一点击流程中完成。
  3. 多 series、多 title 用数组组织;先定位置和大小骨架,再填数据,验收更高效。
  4. 饼图数据必须明确映射为 { value, name },男女数据源要分清 b_count 与 g_count。
  5. 示例配置不能照搬,roseType、legend、圆角等不需要的项要主动删除,避免干扰视觉。
  6. 看板验收重点看数据对应、图形不重叠、tooltip 可用、按钮高亮正确。
  7. 交付前必须同时检查本地提交和远程推送,避免只 commit 未 push。