Skip to content

首页顶部第三个卡片完成与完成顶部四个卡片(Day11 2/2) ​

本页对应 day11,共 5 段视频,约 1 小时 44 分。

学习目标 ​

  • 能使用 ECharts 柱状图组件接收并替换首页顶部卡片数据,正确配置坐标轴、柱条宽度、背景色及 label 格式化内容。
  • 能基于 ECharts 柱状图实现横向进度条效果,隐藏无关坐标轴、设置坐标轴最大最小值,并调整布局与颜色。
  • 能使用 Element Plus 的 Tabs、日期选择器等组件完成首页中间区域静态结构搭建,并通过定位或弹性布局实现左右、上下结构。
  • 能使用深度选择器修改 Element Plus 组件内部样式,并验证文字、背景色、间距等样式生效。
  • 能使用日期范围选择器完成日历数据收集,配置 value-format,并使用 dayjs 格式化日期、计算今日/本周/本月/本年的起止日期。
  • 能说明菜单权限与按钮权限的实现思路,包括路由拆分、用户信息过滤动态路由、addRoute 追加路由及自定义指令控制按钮显示。

知识点 ​

本节要完成什么 ​

本节聚焦首页顶部第三个卡片:今日交易用户数。它前面已经有写死的柱状图,现在要把写死数据换成父组件传进来的接口数据,并完成图表样式微调。转写里同时提到后台管理系统文档的使用,这里一并整理。

后台管理系统文档:先学会查,再动手写 ​

为什么需要:后台管理系统需求多、组件多,工作里不可能每个都从零写;组件库文档和需求区就是现成参考。转写里说“以后工作了写这种后台管理系统项目,你就翻这个文档”,练习时也可以把它当文档看。

怎么想:先找同类需求,看别人怎么用组件、怎么组织数据;但项目字段要以自己的接口为准,不能照抄示例。

怎么做:翻文档找组件示例,再看需求区有没有类似场景;缺需求可以提需求。转写提到“将近两三万已经写好了的需求”,说明可参考内容很多。

易错点:文档示例是“用法”,不是“业务代码”。替换到项目里时,要确认字段名、数据层级、空数据情况,别把示例数据直接当成接口数据。

第三个卡片:从写死数据到接口数据 ​

为什么需要:柱状图不能一直写死,否则首页展示的不是真实交易用户数。

怎么想:先确认图表组件需要什么数据,再去父组件找对应接口字段。转写里的顺序是:先看写死的柱状图,再找“今日交易用户数”的数据,最后把数据传给子组件。

怎么做:父组件里把接口返回的数据接到 ARR,再传给卡片组件;子组件用 defineProps 接收。模板里可以直接用 arr,但在脚本/配置函数里要用接收后的对象,例如转写口述的 d.arr。

js
// 父组件:把接口返回的数据交给 ARR
ARR = 后端返回的数据

// 模板中传给第三个卡片
<ThirdCard :arr="ARR" />
js
// 子组件:接收父组件传入的数据
const d = defineProps({
  arr: Array
})

// 图表数据处使用
data: d.arr

易错点:props 在模板中可直接写,但在脚本里要先接收;转写反复强调“模板里直接写它,TS 里用数据得接收”。另外,父组件字段要找对,转写里说“第 10 行”“今日交易用户数”,就是提醒先定位字段再替换。

刷新调试:配置为什么执行两次 ​

为什么需要:替换数据后必须刷新验证,确认图表拿到的是接口数据,而不是旧写死值。

怎么想:先看图表有没有数据,再看配置函数执行时数据是否已经到达。转写里刷新后发现配置项执行了两次,第一次没数据,第二次有数据。

怎么做:打开页面刷新,观察图表;在配置函数里打印 d.arr,确认第一次为空、第二次有值。然后把写死数据替换成 d.arr。

易错点:配置执行两次不是 bug,而是组件在监测数据变化。第一次数据没到,第二次数据到了才渲染。不要在第一次空数据时强行取值导致报错。

组件封装的好处:空数据不用自己判断 ​

为什么需要:真实接口有延迟,初始数据可能为空;如果图表组件不处理,就容易报错或白屏。

怎么想:转写对比了以前写原生图表时要写 v-if 判断数据,而现在用的 vue-echarts 组件已经帮忙处理空数据。

怎么做:把数据交给组件,组件内部监测数据变化;空数据时先不渲染有效图形,有数据后自动更新。转写说“这玩意儿你就不用管,人家都帮你备好”。

易错点:虽然组件帮你处理,但父组件传参仍要保证类型正确,默认值最好是空数组;不要因为组件能处理就传 undefined。

样式微调:label 与柱条宽度 ​

为什么需要:只有柱子不够,业务上常要把数值展示在柱条上,还要控制柱条宽度和颜色。

怎么想:这些都归图表配置管。转写提到“label 把这个值在柱状展示”“每个柱条颜色能不能调”“柱条宽度可以调”。

怎么做:在 series 里配置 label.show 显示文本,label.color 调文字颜色,barWidth 调柱条宽度。转写里柱宽试了 10 像素。

js
series: [{
  type: 'bar',
  data: d.arr,
  barWidth: 10,
  label: {
    show: true,
    color: 'red'
  }
}]

易错点:barWidth 不是 width;文字颜色写在 label.color 下,不要写到 series 顶层。调完样式要刷新看实际效果,别只看配置项。

本节小结 ​

第三个卡片完成的关键不是“画一个柱状图”,而是把父组件接口数据 → 子组件 props → 图表配置这条链接通。调试时重点看两件事:字段有没有找对、数据第一次为空第二次到达时组件有没有正常更新。最后再用 label 和 barWidth 做展示优化。转写里“配置执行两次”的现象要理解成数据监测过程,不要误判为错误。

本节目标与整体思路 ​

为什么需要:首页顶部四个卡片是后台管理系统的数据总览区,前两个卡片已经完成,第三个“今日交易用户数”要用柱状图展示,第四个“累积用户数”要用进度条展示。它们不是孤立样式,而是“接口数据 → 子组件接收 → 图表配置 → 页面呈现”的完整练习。

怎么想:先完成第三个卡片的数据接入,再做第四个卡片的进度条。第三个卡片重点是把父组件拿到的数组传给图表组件;第四个卡片重点是用“横向柱状图”模拟进度条,而不是再写一个水球图。

怎么做:父组件把接口返回的数组通过属性传给子组件;子组件用 defineProps 接收,模板中直接使用,TS 逻辑中通过 props 取值;图表组件用配置对象控制坐标轴、系列、柱宽、背景和标签。

易错点:转写稿里的“de范proers”应纠正为 defineProps;“getOP”是 getOption;“SA叉XX轴”是 xAxis,“YH叉SY轴”是 yAxis,“SERNEX”是 series。配置项一般叫 option,不是 options。

第三个卡片:今日交易用户数柱状图接数据 ​

为什么需要:之前柱状图的数据是写死的,只能看效果;真实项目必须从接口返回的数据中取“今日交易用户数”,否则图表没有业务意义。

怎么想:先在父组件确认接口数据里哪个字段对应今日交易用户数,再把该数组传给柱状图子组件。转写稿中反复确认“第几个数据”“是不是这个”,说明字段不能凭感觉,要对着数据源核对。

怎么做:父组件把对应数组传给子组件;子组件用 defineProps 接收,例如接收 ARR。模板中可以直接写 ARR;如果在 TS 函数里使用,则要先接收 const props = defineProps(...),再通过 props.ARR 取。原来写死的数据替换成接收值后刷新页面。

调试过程:转写稿提到配置项会执行两次,第一次没有数据,第二次才有数据。这不是错误,而是组件在监测数据变化:接口数据未到时先执行一次,数据到达后再次执行。项目里的图表组件已经帮我们处理了空数据,所以不必像早期手写图表那样额外写 v-if 判断。

易错点:不要误以为执行两次是 bug;不要在模板里写 props.ARR 又在 TS 里直接写 ARR;字段名要对准接口;组件名首字母要大写,避免和原生标签冲突。

第四个卡片:用横向柱状图实现进度条 ​

为什么需要:进度条能直观表达“当前值占目标值的比例”,比如 80% 就到接近末端,50% 在中间。它比水球图更常见,也更适合累积用户数这类指标。

怎么想:不要把它想成新组件,它的本质是柱状图:背景是一条灰色横条,前景是一条有颜色的横条,横轴范围是 0 到 100。竖着看是柱状图,横着看就是进度条。

怎么做:先搭卡片结构,再引入进度条组件。配置时把 xAxis 和 yAxis 的关系调换,让柱条横向分布;隐藏 yAxis;设置 xAxis 的 min 为 0、max 为 100;用 grid 把上下左右边距调小;series 的 type 设为柱状图;用 barWidth 调柱条宽度;用 showBackground 配合 backgroundStyle 设置灰色背景;用 label 的 formatter 自定义文字内容,用 position 调整标签位置。

调试过程:先做出竖向柱状图,再改成横向;发现柱条太宽就调 barWidth;发现没有灰色底条就检查是否加了 showBackground;想让标签显示百分号或自定义文本,就用 formatter;标签位置不对就调 position,横向时通常在右侧或上方。

易错点:option 不要多写 s;进度条组件名要规范,避免和原生标签混淆;label.formatter 是自定义标签内容的,不是直接改数值;颜色和文字样式可以用深度选择器调整,但先确认选择器是否命中了正确的类名。

完成顶部四卡后的检查清单 ​

为什么需要:四个卡片容易“各自能跑,合起来乱”,必须统一检查数据、样式和空值表现。

怎么想:按“数据是否接对、配置是否生效、空数据是否正常、样式是否统一”四项检查。

怎么做:刷新页面看第三个卡片是否用真实数组;看第四个卡片是否按 0 到 100 的比例显示;检查柱条宽度、背景色、标签文字;检查父组件传参名和子组件接收名是否一致。

易错点:不要把“配置执行两次”当成异常;不要漏掉 props 接收;不要用错坐标轴;不要忘记 showBackground 和 backgroundStyle 要配合使用。

中间区域先搭骨架:卡片与选项卡 ​

为什么需要:首页中间是主要信息区,既要放图表,又要放门店销售额等辅助信息。先把静态骨架搭出来,后续接数据、做交互时才有稳定的落点。
怎么想:转写稿里明确说“中间这里的东西我们就不拆出组件了”,所以这一节先在首页组件内用 el-card 包住头部和内容区,不急着拆子组件。
怎么做:先放一个卡片,顶部再放选项卡和日期选择器,底部用栅格分成左右两列。代码可以先写成这样:

vue
<el-card>
  <div class="header">
    <el-tabs v-model="activeName">
      <el-tab-pane label="销售额" name="sale"></el-tab-pane>
      <el-tab-pane label="访问量" name="visit"></el-tab-pane>
    </el-tabs>

    <el-date-picker
      v-model="dateArr"
      type="daterange"
      range-separator="至"
      start-placeholder="入住时间"
      end-placeholder="离开时间"
      size="small"
    />
  </div>

  <el-row>
    <el-col :span="18">图表区域</el-col>
    <el-col :span="6">门店销售额</el-col>
  </el-row>
</el-card>

易错点:el-tabs 的 name 要和 v-model 的值对应;el-col 的 span 相加不要超过 24,否则会换行。静态阶段先不接数据,但 v-model 可以先占位,方便后面继续做日历业务。

选项卡的选中值与文字 ​

为什么需要:选项卡默认选中项如果不是“销售额”,页面一进来高亮就会错。
怎么想:转写稿里调试时发现默认亮的是别的项,于是用 v-model 收集当前选中的 name,再把初始值改成销售额对应的 sale。
怎么做:定义 const activeName = ref('sale'),模板里写 v-model="activeName";选项卡文字用 label="销售额"、label="访问量"。
易错点:name 是标识,label 是显示文字,二者不要混;改文字只改 label,不要改 name,否则选中值会对不上。

日期范围选择器放进头部右侧 ​

为什么需要:首页中间需要按“今日、本周、本月、本年”或起止日期筛选,日期选择器是常见入口。
怎么想:转写稿里先试了单个日期选择器,发现不是想要的“开始和离开”两个输入框,最后确定用 type="daterange"。
怎么做:用 range-separator="至" 改中间分隔符,用 start-placeholder、end-placeholder 改占位文字,用 size="small" 让它在头部不显得过大。
易错点:只有 daterange 才会出现起止两个输入框;v-model 绑定的是数组,不是单个字符串。静态阶段可以先不处理数据格式,后面再补 value-format。

用栅格把图表区一左一右排开 ​

为什么需要:底部左侧是主图表,右侧是门店销售额,必须一左一右,否则信息层级不清。
怎么想:转写稿里说“一行两列”,左侧占 18 份,右侧占 6 份,正好 24 份。
怎么做:外层 el-row,里面两个 el-col,分别写 :span="18" 和 :span="6";也可以后续换成 flex,但静态阶段栅格更直接。
易错点:不要给 el-col 写死宽度破坏栅格;左右两列之间需要间距时,优先用 gutter 或外层样式,不要靠空格硬撑。

样式微调用深度选择器 ​

为什么需要:Element Plus 的选项卡默认颜色和项目设计不一致,需要改文字颜色和下方指示条颜色。
怎么想:转写稿里先改 .el-tabs__item,发现文字变了但下面小球没变;继续审查元素找类名,最后确认要改背景色。
怎么做:用 :deep() 穿透组件样式,例如:

css
.header {
  display: flex;
  justify-content: space-between;
}

:deep(.el-tabs__item) {
  color: yellowgreen;
}

:deep(.el-tabs__active-bar) {
  background-color: yellowgreen;
}

易错点:不要凭感觉猜类名,第一次没生效就打开浏览器审查元素确认;改颜色时区分 color 和 background-color,文字颜色和指示条背景色不是同一个属性。转写稿里正是通过反复审查元素,才从“改文字”走到“改背景色”。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

课堂画面 5

代码示例 ​

示例1:ECharts 横向进度条(第四个卡片) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>横向进度条</title>
  <script src="https://unpkg.com/echarts/dist/echarts.min.js"></script>
  <style>
    body {
      margin: 40px;
      font-family: Arial, sans-serif;
    }
    .progress-card {
      width: 360px;
      padding: 20px;
      border: 1px solid #eee;
      border-radius: 8px;
    }
    .progress-chart {
      width: 100%;
      height: 40px;
    }
  </style>
</head>
<body>
  <div class="progress-card">
    <div id="chart" class="progress-chart"></div>
  </div>

  <script>
    const chart = echarts.init(document.getElementById('chart'));

    chart.setOption({
      grid: {
        left: 0,
        top: 0,
        right: 0,
        bottom: 0
      },
      xAxis: {
        type: 'value',
        min: 0,
        max: 100,
        show: false
      },
      yAxis: {
        type: 'category',
        data: [''],
        show: false
      },
      series: [
        {
          type: 'bar',
          data: [86],
          barWidth: 10,
          showBackground: true,
          backgroundStyle: {
            color: '#ccc'
          },
          itemStyle: {
            color: '#409eff'
          },
          label: {
            show: true,
            position: 'right',
            formatter: '{c}%',
            color: 'red'
          }
        }
      ]
    });
  </script>
</body>
</html>

要点解释:

  • yAxis.type = 'category' 让柱状图横向排列;xAxis.min = 0、max = 100 控制百分比范围。
  • 柱条背景色必须用 series.showBackground + series.backgroundStyle 成对配置,不是写在 itemStyle 里。
  • barWidth 控制柱条宽度;label.position = 'right'、formatter、color 分别控制数值位置、内容和颜色。
  • 易错点:横向柱状图不是改 type: 'bar' 就够,必须让类目轴在 yAxis;label 的 position 在横向柱状图中常用 right。

示例2:Element Plus 日期范围 + 今日/本周/本月/本年 ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>日期范围快捷选择</title>
  <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css" />
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script src="https://unpkg.com/element-plus/dist/index.full.js"></script>
  <script src="https://unpkg.com/dayjs/dayjs.min.js"></script>
  <style>
    body {
      margin: 40px;
      font-family: Arial, sans-serif;
    }
    .calendar-card {
      display: flex;
      align-items: center;
      gap: 10px;
    }
    .left span {
      color: yellowgreen;
      margin-right: 10px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div id="app">
    <div class="calendar-card">
      <div class="left">
        <span @click="setToday">今日</span>
        <span @click="setWeek">本周</span>
        <span @click="setMonth">本月</span>
        <span @click="setYear">本年</span>
      </div>

      <el-date-picker
        v-model="dateRange"
        type="daterange"
        range-separator="至"
        start-placeholder="入住时间"
        end-placeholder="离开时间"
        value-format="YYYY-MM-DD"
        size="small"
      ></el-date-picker>
    </div>

    <p>当前值:{{ dateRange }}</p>
  </div>

  <script>
    const { createApp, ref } = Vue;

    createApp({
      setup() {
        const dateRange = ref([]);

        const fmt = (d) => d.format('YYYY-MM-DD');

        const setToday = () => {
          const d = dayjs().format('YYYY-MM-DD');
          dateRange.value = [d, d];
        };

        const setWeek = () => {
          const start = dayjs().day(1);
          const end = start.add(6, 'day');
          dateRange.value = [fmt(start), fmt(end)];
        };

        const setMonth = () => {
          const start = dayjs().startOf('month');
          const end = dayjs().endOf('month');
          dateRange.value = [fmt(start), fmt(end)];
        };

        const setYear = () => {
          const start = dayjs().startOf('year');
          const end = dayjs().endOf('year');
          dateRange.value = [fmt(start), fmt(end)];
        };

        return {
          dateRange,
          setToday,
          setWeek,
          setMonth,
          setYear
        };
      }
    }).use(ElementPlus).mount('#app');
  </script>
</body>
</html>

要点解释:

  • el-date-picker 的 type="daterange" 对应开始/结束两个日期,v-model 绑定的是数组。
  • value-format="YYYY-MM-DD" 决定收集到的数据格式;不写容易拿到 Date 对象或格林尼治格式,不利于提交后台。
  • 点击“今日/本周/本月/本年”本质是改 dateRange 数组,组件会双向绑定回显。
  • 易错点:dayjs().startOf('week')/endOf('week') 按老外习惯周日开始,国内项目要注意周一边界;转写稿中使用 dayjs().day(1) 表示周一,实际项目要处理周日边界。

示例3:首页中间静态搭建(el-card + el-tabs + el-row/el-col) ​

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <title>首页中间静态搭建</title>
  <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css" />
  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  <script src="https://unpkg.com/element-plus/dist/index.full.js"></script>
  <style>
    body {
      margin: 40px;
      font-family: Arial, sans-serif;
    }
    .middle-card {
      margin: 10px 0;
    }
    .header {
      position: relative;
      margin-bottom: 10px;
    }
    .right {
      position: absolute;
      right: 0;
      top: 0;
    }
    .right span {
      color: yellowgreen;
      margin-left: 5px;
      cursor: pointer;
    }
    .chart-box,
    .rank-box {
      height: 260px;
      background: #f5f7fa;
      display: flex;
      align-items: center;
      justify-content: center;
      color: #999;
    }
  </style>
</head>
<body>
  <div id="app">
    <el-card class="middle-card">
      <div class="header">
        <el-tabs v-model="activeName">
          <el-tab-pane label="销售额" name="sales"></el-tab-pane>
          <el-tab-pane label="访问量" name="visits"></el-tab-pane>
        </el-tabs>

        <div class="right">
          <span>今日</span>
          <span>本周</span>
          <span>本月</span>
          <span>本年</span>
        </div>
      </div>

      <el-row :gutter="10">
        <el-col :span="18">
          <div class="chart-box">图表区域</div>
        </el-col>
        <el-col :span="6">
          <div class="rank-box">门店销售额</div>
        </el-col>
      </el-row>
    </el-card>
  </div>

  <script>
    const { createApp, ref } = Vue;

    createApp({
      setup() {
        const activeName = ref('sales');
        return { activeName };
      }
    }).use(ElementPlus).mount('#app');
  </script>
</body>
</html>

要点解释:

  • el-tabs 的 v-model 绑定 activeName,el-tab-pane 的 name 对应切换值;默认 sales 时“销售额”高亮。
  • el-row 一行 24 栅格,el-col :span="18" 与 :span="6" 形成左侧图表、右侧门店销售额布局。
  • 右侧“今日/本周/本月/本年”用绝对定位固定在头部右上角,避免 flex 撑开 tabs 宽度的问题。
  • 易错点:Element Plus 组件内部样式在 scoped 中常需 :deep() 深度选择器;栅格 span 总和应为 24;el-tabs 的 name 不要和 label 混用。

常见错误 ​

  1. 现象:父组件传了数组,子组件模板里 {{ arr }} 能渲染,但 TS 逻辑里写 arr.xxx 直接报红/运行时 undefined。 原因:defineProps 只在模板作用域自动展开,<script setup> 里必须显式接住才能当变量用。 修法:const props = defineProps<{ arr: XXX[] }>(),逻辑里一律 props.arr;别在模板里混用两种写法。

  2. 现象:ECharts 组件初始化后图表空白,控制台报 option 相关错误,或改了 option 名字却不生效。 原因:配置项名写错(如写成 getOptions / options 复数),或 option 是普通对象导致数据更新后视图不刷新。 修法:对照文档确认是 getOption(无 s);数据变化需重算的用 computed 生成 option,避免一次性写死。

  3. 现象:想用柱状图做横向进度条,结果柱子还是竖着、Y 轴刻度文字挡在前面、条宽巨粗。 原因:只改了 series.type,没把类目轴换到 yAxis;轴线和刻度没隐藏;没设 barWidth。 修法:xAxis 设为数值轴(min:0 / max:100 并隐藏轴线),yAxis 设为 type:'category' 并 show:false,series 加 barWidth 与 backgroundStyle。

  4. 现象:用 ::v-deep .el-tabs__item { color: xxx } 改 Element Plus 样式,刷新后毫无变化。 原因:选择器名猜错(实际是 el-tabs__active-bar / el-tabs__nav-wrap 等),或改的是文字色而实际要改的是背景色,或预处理器语法不对(less 用 /deep/、scss 用 ::v-deep/:deep())。 修法:先在浏览器审查元素拿到准确类名与准确属性(color 还是 background-color),再写深度选择器;改不到就往上找父级容器统一改。

  5. 现象:日期范围选择器选完,v-model 拿到的是 ['2023-09-04', ...] 之外的奇怪格式,或回显时页面不亮。 原因:没配 value-format,默认给的是 Date 对象;或 v-model 绑的是字符串而非数组。 修法:加 value-format="YYYY-MM-DD",v-model 绑定 ref<string[]>([]),回显时按同格式塞值。

  6. 现象:点“本周”,日期区间变成周日~周六,和国内习惯(周一~周日)对不上。 原因:dayjs / moment 的 startOf('week') 默认按西方习惯以周日为一周起点。 修法:改用 dayjs().day(1) 手动取周一,或引入 weekStart: 1 的 locale 配置;月/年用 startOf('month')、startOf('year') 无此问题。

  7. 现象:头部“今日/本周/本月/本年”与右侧日期选择器用 flex 一左一右,结果日期选择器宽度被文字撑开、换行错位。 原因:日期组件在 flex 容器里没有固定宽度,被内容压缩。 修法:给日期组件设 width 或 flex: none,或干脆放弃 flex、对日期块用绝对定位贴右上角。

练习 ​

  1. 把顶部第三个卡片的柱状图数据从写死改为 props 传入,并保证父组件异步拿到数据后图表能刷新(提示:option 用 computed)。
  2. 用横向柱状图完成第四个卡片的进度条:值为 86 时条长占 86%,右侧显示自定义文字“86%”,底色为浅灰、条为渐变绿。
  3. 用 dayjs 实现“今日/本周/本月/本年”四个按钮,点击后把 [开始, 结束] 写回日期选择器的 v-model,要求本周按周一起算,并验证回显。
  4. 用深度选择器把 Element Plus 选项卡的激活文字色改为黄绿色、底部滑块背景色改为同色,写出 scss 与 less 两种写法。
  5. 自定义一个 v-has 指令:传入按钮权限标识数组,当前用户权限数组中不存在该标识时移除该 DOM,并在登录成功后验证效果。

原视频对照 ​

#视频时长
1首页顶部第三个卡片完成07:16
2完成顶部四个卡片18:45
3完成首页中间静态的搭建21:29
4中间组件日历业务的完成38:25
50904_16160318:57

小结 ​

  1. 图表类卡片的数据流固定为“父组件取数 → props 下发 → 子组件 computed 生成 option”,写死数据只适合搭静态阶段。
  2. 进度条不必新造轮子,横向柱状图 + backgroundStyle + label.formatter 即可,barWidth 控制粗细。
  3. 第三方 UI 组件的样式修改,正确姿势是“审查元素拿准类名 → 深度选择器 → 改对属性”,猜类名是最常见的无效劳动。
  4. 日期类交互的核心是“格式统一”:value-format 决定收集格式,dayjs 决定计算与展示格式,两头必须一致。
  5. dayjs 与 moment 的 API 高度一致,会用其一即可迁移;但 startOf('week') 的西方起点是必须记住的坑。
  6. 选项卡用 v-model 绑定 name 值即可完成高亮切换,切换内容区靠 name 匹配,不必自己写激活逻辑。
  7. 菜单权限三步走:拆静态/异步/任意路由 → 登录后按用户标识过滤 → router.addRoute 动态追加;按钮权限一句话概括为自定义指令按标识判断。
  8. 布局能用 flex 就别用绝对定位;只有“必须贴角且不参与流”的元素(如右上角日期块)才用 position: absolute。