Skip to content

完成首页中间柱状图与左侧排名(Day12 1/2) ​

本页对应 day12(1),共 5 段视频,约 1 小时 40 分。

学习目标 ​

  • 能够使用 ECharts 完成首页中间柱状图配置,设置高度、标题、坐标轴、系列、提示框和指示器,并根据“销售额/访问量”动态切换标题与数据。
  • 能够实现左侧排名列表布局,使用 v-for 和 v-if 渲染销售额排名与访问量排名,并对前 3 名应用独立样式。
  • 能够基于 ECharts 官方示例完成雷达图配置,设置容器高度,并调整标题、图例、雷达指标和系列数据。
  • 能够完成饼图配置,设置图例、标签引导线、中心主副标题、高亮效果,并通过鼠标移入事件动态更新中心展示数据。
  • 能够根据“品类/商品”切换饼图数据源,并说明 ECharts 图表实例方法在更新配置项中的应用。
  • 能够说明微信小程序的基本概念、创始人张小龙、无需下载安装即用、用完即走、项目体积限制及常见小程序平台。

知识点 ​

柱状图先解决“有没有高度” ​

为什么需要:ECharts 图表必须有明确高度,否则配置项写得再全也可能不显示。转写稿里反复强调“没高度”是数据可视化最常见的坑。怎么想:先审查元素,确认 v-chart 或父盒子是否被撑开;再决定给图表本身加类名/行内样式,还是给父盒子定高。怎么做:在首页中间卡片左侧放 v-chart :option="option",先给 height: 400px(调试时可改 300px),也可让父盒子有高度后让图表继承。易错点:只看代码不看元素;左侧 left、底部 bottom 不要归零,否则 Y 轴刻度、X 轴文字会看不见;右侧没有双坐标时可 right: 0。转写稿未给完整代码,以下只保留出现过的配置项名称:

js
// 仅按转写稿整理关键配置项,不补全未出现的值
v-chart :option="option"
height: 400px
title: { text, left: 'center', textStyle: { color } }
xAxis: { type: 'category', data, axisPointer: { type: 'shadow' } }
yAxis: { axisLine: { show: true }, axisTick: { show: true } }
series: [{ type: 'bar', data, itemStyle: { color }, label: { show: true } }]
tooltip: { axisPointer: { type: 'shadow' } }

标题、坐标轴和 12 个月数据 ​

为什么需要:柱状图要表达“1—12 月销售额/访问量”,必须有标题、分类轴、数值轴和系列数据。怎么想:先搭最小可显示结构,再调布局。怎么做:title.text 先写“销售额”,xAxis.type 用类目轴,series.type: 'bar' 放 12 条数据;布局用 left: 30、bottom: 30、right: 0 留出刻度空间。易错点:标题居中不是靠猜,用 left: 'center';轴线和刻度要分别用 axisLine.show、axisTick.show 打开;X 轴默认显示 0—11 索引,需要把月份数组绑定到 xAxis.data。

tooltip、指示器和柱条样式 ​

为什么需要:鼠标移入要看到提示,柱条颜色和数值标签也要符合设计。怎么想:先查 ECharts 官网实例,找相近效果直接 CV 再调。怎么做:tooltip 配提示框,axisPointer.type: 'shadow' 做阴影指示器;itemStyle.color 调柱条颜色(可用渐变);label.show: true 让数值显示。易错点:axisPointer 放 tooltip 还是 xAxis 要按官网示例确认;找不到效果时不要盲改,先看实例里触发时机和配置位置。

标题与数据随“销售额/访问量”切换 ​

为什么需要:同一个图表要复用于两个指标。怎么想:父组件已通过 activeName 收集当前选项,标题可用三元判断,数据从父组件传入的两组数组中二选一。怎么做:模板中判断 activeName === 'sales' 显示“销售额”,否则“访问量”;props 接收父组件 data,用 v-if/v-else 或计算属性切换 series.data。易错点:模板里会自动解包,JS 区域要 .value;v-if 与 v-for 不要随意放同一元素,V3 中 v-if 优先级更高。

左侧排名:静态结构、flex 与前三名样式 ​

为什么需要:右侧排名不是图表,用 ul/li 更直接。怎么想:每个 li 分名次、名称、数值三部分,用 flex 做一左一右;前 3 名加特殊类。怎么做:v-for 渲染数组,index < 3 时加类名;主轴用 justify-content: space-between,名次小球用固定宽高、border-radius: 50%、文字居中;两组数据按 activeName 二选一。易错点:key 要稳定;前 3 名样式不要写成所有项;v-if/v-else 切换数组时注意数据字段名不同。

雷达图、饼图:先找官网示例再调 ​

为什么需要:工作里图表配置项很多,不必从零手写。怎么想:先搜 ECharts 官网实例,有相似效果就复制,再换真实数据。怎么做:雷达图给高度,调 legend、数据;饼图用 radio 收集“品类/商品”,数据二选一,label 做视觉引导线,中间文字可用 title 主副标题调 left/top;鼠标移入可用 mouseover 拿到 params,通过 setOption 改标题。易错点:饼图 label 默认在中间,要移到外侧;legend 方向和位置可调;事件参数是 params,不是随便命名。

小程序简介 ​

为什么需要:后续进入移动端和小程序。怎么想:微信小程序由张小龙/腾讯推出,特点是无需安装、用完即走,但实际仍需下载小体积包。怎么做:记住上线体积限制不超过 2MB;后续用真机测试。易错点:不是“完全不用下载”;市场上有百度、支付宝、钉钉等小程序,但本节学的是微信小程序。

本节笔记未附图片,以下保留转写稿中的关键代码。本节完成首页排名列表(笔记标题为“左侧排名”):销售额/访问量切换时,标题和列表数据同步变化。

需求与数据来源 ​

为什么需要:首页数据可视化不能只有柱状图,还要让用户快速看到门店销售额或访问量的排名,所以排名列表要跟着顶部指标切换。

怎么想:排名列表不画图表,本质是“标题 + 列表”。标题由当前选中指标决定;列表数据由父组件提供,销售额和访问量各一个数组,二者取其一。

怎么做:父组件把首页数据通过 props 传给排名组件,模板中可直接访问 data;列表用 ul > li,每个 li 放三部分:名次、门店名、数值。

易错点:转写稿调试时特别提醒,模板里会自动解包 ref,写 activeName 即可;在 script 里才写 activeName.value。另外访问量数组没有 id 时,转写稿用索引作 key,有唯一 id 时应优先用 id。

标题随指标切换 ​

为什么需要:用户选“销售额”时标题应是“门店销售额排名”,选“访问量”时变成“门店访问量排名”,否则标题和数据对不上。

怎么想:用三元表达式判断当前指标,activeName === 'sale' 时显示销售额排名,否则显示访问量排名。

怎么做:

html
<h1>{{ activeName === 'sale' ? '门店销售额排名' : '门店访问量排名' }}</h1>

易错点:转写稿里标题一开始受全局 h1

先搭底部卡片:雷达图放在哪里 ​

为什么需要:首页底部要放两个卡片,左侧卡片头部有“关键字搜索”和下拉菜单,下面才是雷达图。先把容器和头部搭好,图表才有稳定父级和高度。

怎么想:转写稿里先处理布局:左右两个 el-col,里面放 el-card;卡片头部不能用默认标题,而要用具名插槽 header 自定义,因为默认头部有贯穿分割线,而设计稿头部是自定义内容。

怎么做:卡片内用 header 插槽,左侧写“关键字搜索”,右侧放下拉菜单 el-dropdown;外层用 flex 的 space-between 让左右分开。下拉菜单可先用“北京、上海”等静态项占位。下拉箭头图标可保留,也可按转写稿用深度选择器调样式。

易错点:① 忘记用 header 插槽,头部结构不对;② 下拉菜单默认是点击触发,不是鼠标移入;③ 改第三方组件样式要用深度选择器;④ 父容器没高度时,后面图表不显示。

雷达图先找官方实例,不要从零硬写 ​

为什么需要:转写稿反复强调:工作里写图表不是一个个配置项硬背,而是先看 ECharts 官网实例,有类似效果就复制过来再调。雷达图就是典型。

怎么想:先明确需求是“多维指标对比”,所以选雷达图;到 ECharts 官网搜“雷达图”,找最接近的实例,把配置项整体拿过来,再替换标题、图例、指标名和数据。

怎么做:容器写 v-chart :option="getRadar",并给高度,例如 height: 300px。配置项里保留 title、legend、radar.indicator、series。标题先改成“王者荣耀”;图例改成“男生、女生”这类两项;指标名改成“生存、发育、猥琐别浪、坚持”等;系列 type 为 radar,数据用两个数组占位。刷新后能看到雷达图,再按接口数据替换。

易错点:① 没给高度,图表不出来,先审查元素看容器高度;② 配置项记不住就查官网实例,不要懵;③ legend 的名字要和 series.data 对应;④ 指标名、最大值、文字颜色都可调,但不要一次改太多,改一项刷新验证一项。

调图例和指标:位置、方向、文字 ​

为什么需要:官网实例只是起点,设计稿的图例位置、方向、指标文字都不一样,必须会调。

怎么想:图例由 legend 控制,位置可调 right: 0 等,方向可调 orient: 'vertical';指标文字在 radar.indicator 里改 name,最大值也可设;文字颜色可在对应样式里调。

怎么做:先把 legend.right 设为 0,看是否贴边;再把 orient 改成 vertical,看是否竖排;然后改 indicator 的 name,如“生存、发育、猥琐别浪、坚持”;刷新验证。转写稿里还提到图例方向有水平/竖着两种,调完就能看到变化。

易错点:① 把 legend 和 radar 配错位置;② 改了 name 但数据没对应;③ 图例贴边后遮挡图形,要结合容器宽度调;④ 不要忘记 series 里 type: 'radar'。

调试顺序与同页图表思路 ​

为什么需要:转写稿的调试过程是“先复制实例→补高度→改标题→改图例→改指标→刷新看效果”。这个顺序能快速定位问题。

怎么想:先保证“能显示”,再保证“像设计稿”,最后替换真实数据。同页还有 K 线图、饼图,思路一样:官网找实例、复制配置项、调样式、换数据。

怎么做:雷达图完成后,检查容器高度、标题、图例、指标、数据五项;接口有数据时替换 series.data 和 indicator 对应值。转写稿提到“K线图直接带走配置项”“饼图也是官网实例基础上调”,说明不要重复造轮子。

易错点:① 只复制不调,图例和指标对不上;② 忘记真实数据格式可能与示例不同;③ 图表容器高度被父级压掉;④ 第三方组件样式改不动时,先查选择器层级,再用深度选择器。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

代码示例 ​

示例一:首页中间柱状图(ECharts,销售额 / 访问量切换) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>首页中间柱状图</title>
  <style>
    .card { width: 800px; margin: 20px auto; }
    .tabs { display: flex; gap: 10px; margin-bottom: 10px; }
    .tabs button { padding: 4px 12px; cursor: pointer; }
    .tabs button.active { background: #409eff; color: #fff; border-color: #409eff; }

    /* 易错点:图表容器必须给高度,否则 ECharts 画不出来 */
    #barChart { width: 100%; height: 300px; }
  </style>
</head>
<body>
  <div class="card">
    <div class="tabs">
      <button data-type="fail" class="active">销售额</button>
      <button data-type="visit">访问量</button>
    </div>
    <div id="barChart"></div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
  <script>
    // 模拟父组件传过来的首页数据
    const chartData = {
      orderForYear: [120, 200, 150, 80, 70, 110, 130, 100, 90, 160, 140, 180], // 销售额
      userForYear:  [60, 80, 70, 40, 35, 55, 65, 50, 45, 80, 70, 90],          // 访问量
      data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月']
    };

    // 相当于 Vue 里 v-model 收集到的 activeName
    let activeName = 'fail';

    const barChart = echarts.init(document.getElementById('barChart'));

    function getOption() {
      return {
        // 标题:销售额 / 访问量 三元判断,颜色和位置都要调
        title: {
          text: activeName === 'fail' ? '销售额' : '访问量',
          left: 'center',
          textStyle: { color: 'yellowgreen' }
        },
        // 提示框:触发时机 axis,指示器类型 shadow
        tooltip: {
          trigger: 'axis'
        },
        // 布局:left / bottom 千万别归零,否则轴线刻度看不见;right 可以归零
        grid: { left: 30, bottom: 30, right: 0, top: 50 },
        xAxis: {
          type: 'category',
          data: chartData.data,            // 1月 ~ 12月,替换默认的 0~11 索引
          axisTick: { alignWithLabel: true },
          axisPointer: { type: 'shadow' }  // 阴影指示器其实在 X 轴上
        },
        yAxis: {
          type: 'value',
          axisLine: { show: true },        // 左侧轴线
          axisTick: { show: true }         // 左侧刻度
        },
        series: [{
          name: activeName === 'fail' ? '销售额' : '访问量',
          type: 'bar',
          // 数据二选一,和标题的判断套路一模一样
          data: activeName === 'fail' ? chartData.orderForYear : chartData.userForYear,
          itemStyle: {
            // 柱条颜色:渐变
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
              { offset: 0,   color: '#83bff6' },
              { offset: 0.5, color: '#188df0' },
              { offset: 1,   color: '#188df0' }
            ])
          },
          label: { show: true, position: 'inside' } // 文本标签默认就在中间
        }]
      };
    }

    barChart.setOption(getOption());

    // 切换销售额 / 访问量
    document.querySelectorAll('.tabs button').forEach(btn => {
      btn.onclick = () => {
        document.querySelectorAll('.tabs button').forEach(b => b.classList.remove('active'));
        btn.classList.add('active');
        activeName = btn.dataset.type;
        barChart.setOption(getOption(), true);
      };
    });

    window.addEventListener('resize', () => barChart.resize());
  </script>
</body>
</html>

关键行与易错点

  • #barChart { height: 300px }:写数据可视化最要命的问题就是没有高度,图出不来先审查元素看高度,不要瞎改配置项。
  • grid: { left: 30, bottom: 30, right: 0 }:left、bottom 归零会导致左侧刻度和 X 轴文字消失;右侧没有坐标轴,可以归零。
  • yAxis.axisLine.show / axisTick.show:左侧轴线和刻度默认不显示,必须手动打开。
  • title.left: 'center' + textStyle.color:标题居中与颜色是两个位置,别只改一个。
  • tooltip.axisPointer 不生效时,指示器其实挂在 xAxis.axisPointer 上,type: 'shadow'。
  • 标题和 series.data 都用 activeName === 'fail' ? ... : ... 同一个三元判断,二者必须保持一致,否则标题写“销售额”数据却是访问量。

示例二:左侧门店排名列表(flex 一左一右 + 前三名高亮) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>左侧排名</title>
  <style>
    .rank-card { width: 360px; margin: 20px auto; }
    .rank-card h1 { font-size: 16px; }

    .rank-list { list-style: none; padding: 0; margin: 0; }

    .rank-list li {
      display: flex;                  /* 主轴:一左一右 */
      justify-content: space-between; /* 两端对齐,中间留剩余空间 */
      align-items: center;            /* 侧轴:垂直居中 */
      margin: 10px 0;                 /* 每个 li 上下留点距离 */
      font-size: 14px;
    }

    .rank-list li .icon {
      display: inline-block;
      width: 15px;
      height: 15px;
      line-height: 15px;
      text-align: center;
      font-size: 12px;
    }

    /* 前三个:黑底白字 + 圆形(对应模板里 index < 3 动态加类名) */
    .rank-list li:nth-child(-n+3) .icon {
      background: #000;
      color: #fff;
      border-radius: 50%;
    }
  </style>
</head>
<body>
  <div class="rank-card">
    <h1>门店销售额排名</h1>
    <ul class="rank-list">
      <li><span class="icon">1</span><span class="name">华为</span><span class="num">211</span></li>
      <li><span class="icon">2</span><span class="name">小米</span><span class="num">199</span></li>
      <li><span class="icon">3</span><span class="name">vivo</span><span class="num">160</span></li>
      <li><span class="icon">4</span><span class="name">OPPO</span><span class="num">120</span></li>
      <li><span class="icon">5</span><span class="name">荣耀</span><span class="num">99</span></li>
    </ul>
  </div>
</body>
</html>

关键行与易错点

  • 这块没有用到任何图表,纯 ul > li 布局,一个 li 代表一条排名,内部三部分:名次、名字、数量。
  • display: flex + justify-content: space-between:一左一右,中间自动留空;侧轴用 align-items: center。不要再用浮动或写死宽度。
  • 前三个样式不同:纯 CSS 用 li:nth-child(-n+3) .icon;在 Vue 里对应转写稿的写法是 :class="{ icon: true, active: index < 3 }",即 index < 3 时才加高亮类。
  • .icon 先统一 display: inline-block + 固定 15px × 15px,再单独给前三个加 border-radius: 50% 变成小球,否则所有名次都会变成圆圈。
  • 标题要随 tab 变化:activeName === 'fail' ? '门店销售额排名' : '门店访问量排名',两个数据数组也要跟着二选一。

示例三:雷达图(直接抄官网示例,再按需改配置) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>雷达图</title>
  <style>
    /* 易错点:没有高度雷达图同样不显示 */
    #radarChart { width: 500px; height: 300px; }
  </style>
</head>
<body>
  <div id="radarChart"></div>

  <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
  <script>
    const radarChart = echarts.init(document.getElementById('radarChart'));

    radarChart.setOption({
      // 标题
      title: { text: '王者荣耀' },

      // 图例:位置 right 归零贴右边,方向 orient 改成竖着
      legend: {
        right: 0,
        orient: 'vertical',
        data: ['男生', '女生']
      },

      // 雷达图的“坐标轴”:indicator 决定几个维度、每个维度的文字和最大值
      radar: {
        indicator: [
          { name: '生存', max: 100 },
          { name: '发育', max: 100 },
          { name: '猥琐', max: 100 },
          { name: '坚持', max: 100 },
          { name: '团战', max: 100 }
        ]
      },

      series: [{
        type: 'radar',
        // data 是数组,每项用 value + name,name 要和 legend 对得上
        data: [
          { value: [90, 80, 70, 60, 85], name: '男生' },
          { value: [70, 65, 90, 80, 50], name: '女生' }
        ]
      }]
    });

    window.addEventListener('resize', () => radarChart.resize());
  </script>
</body>
</html>

关键行与易错点

  • 这类图表不用自己从零写,先去 ECharts 官网「示例」里找雷达图,配置项直接复制过来,再换成自己的数据,这是工作里的常规做法。
  • #radarChart { height: 300px }:和柱状图一样,容器没高度就是一片空白,不是配置写错了。
  • radar.indicator 里的 name 就是图上的文字,max 决定刻度最大值,改这两项就能换成自己的业务维度。
  • legend.data 和 series.data 里的 name 必须一一对应,否则图例和图形对不上;orient: 'vertical' 是竖排,right: 0 是贴右边。
  • series.type: 'radar',data 里每项是 { value: [...], name: '...' },value 数组长度要和 indicator 的维度数量一致。

常见错误 ​

  1. 图表区域空白:现象是 v-chart 写了但页面无图;原因是图表容器或父容器没有明确高度;修法是给容器或父盒设置固定高度,并用审查元素确认实际高度。
  2. 改第三方组件样式不生效:现象是样式写了但组件外观不变;原因是作用域样式未穿透;修法是用深度选择器包裹目标类名,并确认类名层级。
  3. 切换销售额/访问量后标题或柱状数据不更新:现象是按钮变了图表没变;原因是标题和 series.data 未统一按当前状态二选一;修法是统一用当前选中值判断标题和数据源。
  4. 排名前三样式错乱:现象是前三条和后续样式一样,或第一个圆形没生效;原因是动态类判断或 nth-child 使用不对;修法是用索引 <3 加类,第一个单独用 nth-child(1) 处理。
  5. 饼图鼠标移入后中间数值不更新:现象是悬停高亮但标题/数值不变;原因是只写了静态标题,未监听 mouseover 调 setOption;修法是从事件参数取 name/value,更新主标题和副标题。
  6. 图例或视觉引导线遮挡内容:现象是文字压图、图例位置不合适;原因是 legend、labelLine、radius、left/top 未按容器调整;修法是参考官网实例调图例方向/位置、引导线和半径,预留边距。

练习 ​

  1. 给首页中间柱状图容器补高度,并实现“销售额/访问量”切换时标题和 series.data 同步变化。
  2. 完成左侧排名列表:前三条高亮,第一条排名做成圆形,并验证动态类名只加在前三项。
  3. 从 ECharts 官网找一个雷达图示例接入项目,调整图例位置和标题后说明改了哪些配置项。
  4. 实现饼图鼠标移入时中间标题显示当前项名称和值,移出后恢复到默认项。
  5. 列出小程序项目超过 2MB 时的 3 个排查点和对应处理方式。

原视频对照 ​

#视频时长
1完成首页中间柱状图21:55
2左侧排名15:11
3雷达图17:36
4饼图29:26
5微信小程序简介15:52

小结 ​

  1. 图表类需求先保证容器高度,再排查配置项,审查元素应成为第一反应。
  2. 第三方 UI 组件样式要改,优先确认作用域和深度选择器。
  3. 图表数据切换应由当前选中状态统一驱动,避免标题、数据、图例各写一套。
  4. 复杂图表优先找官网实例改造,再按业务数据替换和微调。
  5. 交互态展示要结合图表事件与 setOption,不能只改静态模板。
  6. 排名、列表类布局要区分索引规则和第一个特殊样式,动态类名要验证。
  7. 小程序入门重点是组件使用和体积限制,上线前要关注资源压缩与真机效果。