Skip to content

04 生命周期

生命周期介绍

  • 思考:什么时候可以发送 初始化渲染请求?(越早越好)什么时候可以开始 操作 dom?(至少 dom 得渲染出来)
  • Vue 生命周期:就是一个 Vue 实例从 创建销毁 的整个过程。

生命周期四个阶段

  • 生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁

  • 创建阶段:创建响应式数据

  • 挂载阶段:渲染模板

  • 更新阶段:修改数据,更新视图

  • 销毁阶段:销毁 Vue 实例

b14afffd-ea22-4728-b7dc-0dde2d6fe2d0

生命周期钩子

  • Vue 生命周期过程中,会 自动运行一些函数,被称为【生命周期钩子
  • 目的:让开发者可以在【特定阶段】运行自己的代码

80c74cff-cf5a-403c-9f75-71ff24c85613

生命周期钩子
html
<div id="app">
  <h3>{{ title }}</h3>
  <div>
    <button @click="count--">-</button>
    <span>{{ count }}</span>
    <button @click="count++">+</button>
  </div>
</div>
<script src="./vue.js"></script>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      count: 100,
      title: "计数器",
    },
    // 1. 创建阶段(准备数据)
    beforeCreate() {
      // 数据还未准备好,现在请求数据会返回 undefined
      console.log("beforeCreate 响应式数据准备好之前", this.count);
    },
    created() {
      // 可以开始发送初始化渲染的请求了,请求数据格式:`this.数据名 = 请求回来的数据`
      console.log("created 响应式数据准备好之后", this.count);
    },

    // 2. 挂载阶段(渲染模板 → 操作 dom)
    beforeMount() {
      // 还未渲染,此时操作 dom 会返回 {{ title }}
      console.log(
        "beforeMount 模板渲染之前",
        document.querySelector("h3").innerHTML
      );
    },
    mounted() {
      // 可以开始操作 dom 了,此时操作会返回值 `计数器`
      console.log(
        "mounted 模板渲染之后",
        document.querySelector("h3").innerHTML
      );
    },

    // 3. 更新阶段 (修改数据 → 更新视图)
    beforeUpdate() {
      // 页面点击后,数据修改,但是 dom 还未更新,此时请求拿到的是更新前的数据 100
      console.log(
        "beforeUpdate 数据修改了,视图还没更新",
        document.querySelector("span").innerHTML
      );
    },
    updated() {
      // 数据修改,dom 也更新了,此时请求拿到的是更新后的数据 101
      console.log(
        "updated 数据修改了,视图已经更新",
        document.querySelector("span").innerHTML
      );
    },

    // 4. 卸载阶段
    beforeDestroy() {
      // 执行 $destroy() 方法后,Vue 实例会被销毁,此时数据还在,dom 还在
      // 一般卸载前会将数据上传至服务器
      console.log("beforeDestroy, 卸载前");
      console.log("清除掉一些 Vue 以外的资源占用,定时器,延时器...");
    },
    destroyed() {
      // 此时数据已经被清除,dom 也被清除
      // 与 vue 相关的资源(事件绑定,事件监听等等)全部失效,已经渲染的数据不会消失
      console.log("destroyed,卸载后");
    },
  });

  // 2s 后卸载组件
  setTimeout(() => {
    app.$destroy();
  }, 2000);
</script>

生命周期案例

新闻列表(created 应用)

案例预览

39da0ff7-be31-4b6c-8a49-d5a714383e24

  • created 数据准备好了,可以开始发送初始化渲染请求
html
<div id="app">
  <ul>
    <li class="news">
      <div class="left">
        <div class="title">5G 商用在即,三大运营商营收持续下降</div>
        <div class="info">
          <span>新京报经济新闻</span>
          <span>2222-10-28 11:50:28</span>
        </div>
      </div>
      <div class="right">
        <img src="http://ajax-api.itheima.net/images/0.webp" alt="" referrerpolicy="no-referrer" />
      </div>
    </li>
    <li class="news">
      <div class="left">
        <div class="title">5G 商用在即,三大运营商营收持续下降</div>
        <div class="info">
          <span>新京报经济新闻</span>
          <span>2222-10-28 11:50:28</span>
        </div>
      </div>
      <div class="right">
        <img src="http://ajax-api.itheima.net/images/0.webp" alt="" referrerpolicy="no-referrer" />
      </div>
    </li>
  </ul>
</div>
<script src="./js/vue.js"></script>
<script src="./js/axios.js"></script>
<script>
  // 接口地址:http://hmajax.itheima.net/api/news
  // 请求方式:get
  const app = new Vue({
    el: "#app",
    data: {},
  });
</script>
html
<div id="app">
  <ul>
    <li class="news" v-for="(item, index) in newsList" :key="item.id">
      <div class="left">
        <div class="title">{{ item.title }}</div>
        <div class="info">
          <span>{{ item.source }}</span>
          <span>{{ item.time }}</span>
        </div>
      </div>
      <div class="right">
        <img :src="item.img" alt="" referrerpolicy="no-referrer" />
      </div>
    </li>
  </ul>
</div>
<script src="./js/vue.js"></script>
<script src="./js/axios.js"></script>
<script>
  // 接口地址:http://hmajax.itheima.net/api/news
  // 请求方式:get
  const app = new Vue({
    el: "#app",
    data: {
      // 新闻列表数据
      newsList: [],
    },
    methods: {
      // 获取新闻列表数据
      async getNewsList() {
        try {
          const res = await axios.get("http://hmajax.itheima.net/api/news");
          console.log(res);
          // 将请求回来的新闻列表数据赋值给 data 中的 newsList
          this.newsList = res.data.data;
        } catch (err) {
          console.log(err);
        }
      },
    },
    // 在 created 钩子函数中调用获取新闻列表数据的方法
    created() {
      this.getNewsList();
    },
  });
</script>

输入框自动聚焦(mounted 应用)

案例预览

5d35fb84-f7ce-450c-a9e0-67a09938d2fc

  • mounted 模板渲染完成,可以开始操作 DOM了。
html
<div class="container" id="app">
  <div class="search-container">
    <img src="./images/logo.png" alt="">
    <div class="search-box">
      <input type="text" v-model="words" id="inp">
      <button>搜索一下</button>
    </div>
  </div>
</div>

<script src="./js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      words: ''
    }
  })
</script>
html
<div class="container" id="app">
  <div class="search-container">
    <img src="./images/logo.png" alt="" />
    <div class="search-box">
      <input type="text" v-model="words" id="inp" />
      <button>搜索一下</button>
    </div>
  </div>
</div>

<script src="./js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      words: '',
    },
    // 核心思路:
    // 1. 等 input 框渲染出来 mounted 钩子
    // 2. 让 input 框获取焦点 inp.focus()
    mounted() {
      // 获取 input 框
      const inp = document.querySelector('#inp');
      // 让 input 框获取焦点
      inp.focus();
    },
  });
</script>

综合案例 小黑记账清单

案例预览

dac8bff7-f5c3-415d-9599-e8daba99ad9b

需求分析

  1. 基本渲染
  2. 添加功能
  3. 删除功能
  4. 饼图渲染

列表渲染 (请求)

  • 立刻发送请求获取数据 created
  • 拿到数据,存到 data 的响应式数据中
  • 结合数据,进行渲染 v-for
  • 消费统计 —> 计算属性
jsx
data: {
  // 帐单列表数据
  billList: [],
},
methods: {
  // 获取帐单列表数据
  async renderBillList() {
    try {
      const res = await axios.get(`https://applet-base-api-t.itheima.net/bill?creator=${creator}`);
      console.log(res);
      this.billList = res.data.data;
    } catch (error) {
      console.log(error);
    }
  },
},
mounted() {
  this.renderBillList();
},
computed: {
  // 计算总金额
  totalPrice() {
    return this.billList.reduce((sum, item) => sum + item.price, 0);
  },
},

<!-- 使用 v-for 遍历 billList -->
<tr v-for="(item, index) in billList" :key="item.id">
  <td>{{index+1}}</td>
  <td>{{item.name}}</td>
  <td :class="{red: item.price > 500}">{{item.price.toFixed(2)}}</td>
  <td><a href="javascript:;">删除</a></td>
</tr>

添加功能

  • 收集表单数据 v-model,使用指令修饰符处理数据
  • 给添加按钮注册点击事件,对输入的内容做非空判断,发送请求
  • 请求成功后,对文本框内容进行清空
  • 重新渲染列表
jsx
<input v-model.trim="billName" type="text" class="form-control" placeholder="消费名称" />
<input v-model.number="billPrice" type="text" class="form-control" placeholder="消费价格" />
<button @click="addBill" type="button" class="btn btn-primary">添加账单</button>

data: {
  ...
  // 消费名称
  billName: '',
  // 消费价格
  billPrice: '',
},
methods: {
  ...
  // 添加账单
  async addBill() {
    // 判断是否输入了消费名称
    if (!this.billName) return alert('请输入消费名称');
    // 判断是否输入了消费价格和是否为数字
    if (!this.billPrice || isNaN(this.billPrice)) return alert('请输入正确的消费价格');

    try {
      const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
        creator,
        name: this.billName,
        price: this.billPrice,
      });
      console.log(res);
      this.billName = '';
      this.billPrice = '';
      this.renderBillList();
    } catch (error) {
      console.log(error);
    }
  },
}

删除功能

  • 注册点击事件,获取当前行的 id
  • 根据 id 发送删除请求
  • 需要重新渲染
jsx
<td><a @click.prevent="delBill(item.id)" href="javascript:;">删除</a></td>

methods: {
  ...
  // 删除账单
  async delBill(id) {
    try {
      const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`);
      console.log(`删除账单:${id}`, res);
      this.renderBillList();
    } catch (error) {
      console.log(error);
    }
  },
},

饼图渲染

ECharts 官网:Apache ECharts 使用教程:快速上手 - Apache ECharts 饼图示例:pie - Apache ECharts

  • 初始化一个饼图 echarts.init(dom)mounted 钩子中渲染
  • 根据数据试试更新饼图 echarts.setOptions({…})
jsx
mounted() {
  ...
  // 饼图渲染
  // 基于准备好的 dom,初始化 echarts 实例
  this.myChart = echarts.init(document.querySelector('#main'));
  // 指定图表的配置项和数据
  const option = {
    // 标题
    title: {
      text: '消费统计',
      subtext: '小黑记账清单',
    },
    // 提示框
    tooltip: {
      trigger: 'item', // 触发类型 item:数据项图形触发 | axis:坐标轴触发 | none:什么都不触发
      formatter: '{a} <br/>{b} : {c} ({d}%)', // 提示框浮层内容格式器
    },
    // 图例
    legend: {
      // orient: 'vertical', // 垂直排列
      // left: 'left',
      top: 'bottom'
    },
    series: [
      {
        name: '消费统计',
        type: 'pie', // 饼图
        radius: [50, 100], // 半径
        center: ['50%', '50%'], // 圆心位置
        // roseType: 'area', // 南丁格尔图
        itemStyle: { // 饼图样式
          borderRadius: 8 // 圆角
        },
        data: [
          // 数据动态渲染,在 methods 中的 renderBillList 方法中渲染(每次请求数据后渲染)
          // { value: 0, name: '餐饮' },
          // { value: 0, name: '交通' },
        ],
        emphasis: { // 高亮样式
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.5)',
          },
        },
      },
    ],
  };
  // 使用刚指定的配置项和数据显示图表
  this.myChart.setOption(option);
},

methods: {
  ...
  // 饼图数据动态渲染
  this.myChart.setOption({
    series: [
      {
        data: this.billList.map(item => ({ value: item.price, name: item.name })),
      },
    ],
  });
},

相关代码

html
<div id="app">
  <div class="contain">
    <!-- 左侧列表 -->
    <div class="list-box">
      <!-- 添加资产 -->
      <form class="my-form">
        <input type="text" class="form-control" placeholder="消费名称" />
        <input type="text" class="form-control" placeholder="消费价格" />
        <button type="button" class="btn btn-primary">添加账单</button>
      </form>

      <table class="table table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>消费名称</th>
            <th>消费价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>1</td>
            <td>帽子</td>
            <td>99.00</td>
            <td><a href="javascript:;">删除</a></td>
          </tr>
          <tr>
            <td>2</td>
            <td>大衣</td>
            <td class="red">199.00</td>
            <td><a href="javascript:;">删除</a></td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
            <td colspan="4">消费总计:298.00</td>
          </tr>
        </tfoot>
      </table>
    </div>

    <!-- 右侧图表 -->
    <div class="echarts-box" id="main"></div>
  </div>
</div>
<script src="./js/echarts.min.js"></script>
<script src="./js/vue.js"></script>
<script src="./js/axios.min.js"></script>
<script>
  /**
   * 接口文档地址:
   * https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
   *
   * 功能需求:
   * 1. 基本渲染
   * 2. 添加功能
   * 3. 删除功能
   * 4. 饼图渲染
   */
  const app = new Vue({
    el: '#app',
    data: {},
  });
</script>
html
<div id="app">
  <div class="contain">
    <!-- 左侧列表 -->
    <div class="list-box">
      <!-- 添加资产 -->
      <form class="my-form">
        <input type="text" class="form-control" placeholder="消费名称" />
        <input type="text" class="form-control" placeholder="消费价格" />
        <button type="button" class="btn btn-primary">添加账单</button>
      </form>

      <table class="table table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>消费名称</th>
            <th>消费价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <!-- 使用 v-for 遍历 billList -->
          <tr v-for="(item, index) in billList" :key="item.id">
            <td>{{index+1}}</td>
            <td>{{item.name}}</td>
            <td :class="{red: item.price > 500}">{{item.price.toFixed(2)}}</td>
            <td><a href="javascript:;">删除</a></td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
            <td colspan="4">消费总计:{{totalPrice.toFixed(2)}} </td>
          </tr>
        </tfoot>
      </table>
    </div>

    <!-- 右侧图表 -->
    <div class="echarts-box" id="main"></div>
  </div>
</div>
<script src="./js/echarts.min.js"></script>
<script src="./js/vue.js"></script>
<script src="./js/axios.min.js"></script>
<script>
  const creator = 'Doraemon';
  const app = new Vue({
    el: '#app',
    data: {
      // 帐单列表数据
      billList: [],
    },
    methods: {
      // 获取帐单列表数据
      async renderBillList() {
        try {
          const res = await axios.get(`https://applet-base-api-t.itheima.net/bill?creator=${creator}`);
          console.log(res);
          this.billList = res.data.data;
        } catch (error) {
          console.log(error);
        }
      },
    },
    mounted() {
      this.renderBillList();
    },
    computed: {
      // 计算总金额
      totalPrice() {
        return this.billList.reduce((sum, item) => sum + item.price, 0);
      },
    },
  });
</script>
html
<div id="app">
  <div class="contain">
    <!-- 左侧列表 -->
    <div class="list-box">
      <!-- 添加资产 -->
      <form class="my-form">
        <input v-model.trim="billName" type="text" class="form-control" placeholder="消费名称" />
        <input v-model.number="billPrice" type="text" class="form-control" placeholder="消费价格" />
        <button @click="addBill" type="button" class="btn btn-primary">添加账单</button>
      </form>

      <table class="table table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>消费名称</th>
            <th>消费价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <!-- 使用 v-for 遍历 billList -->
          <tr v-for="(item, index) in billList" :key="item.id">
            <td>{{index+1}}</td>
            <td>{{item.name}}</td>
            <td :class="{red: item.price > 500}">{{item.price.toFixed(2)}}</td>
            <td><a href="javascript:;">删除</a></td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
            <td colspan="4">消费总计:{{totalPrice.toFixed(2)}} </td>
          </tr>
        </tfoot>
      </table>
    </div>

    <!-- 右侧图表 -->
    <div class="echarts-box" id="main"></div>
  </div>
</div>
<script src="./js/echarts.min.js"></script>
<script src="./js/vue.js"></script>
<script src="./js/axios.min.js"></script>
<script>
  const creator = 'Doraemon';
  const app = new Vue({
    el: '#app',
    data: {
      // 帐单列表数据
      billList: [],
      // 消费名称
      billName: '',
      // 消费价格
      billPrice: '',
    },
    methods: {
      // 获取帐单列表数据
      async renderBillList() {
        try {
          const res = await axios.get(`https://applet-base-api-t.itheima.net/bill?creator=${creator}`);
          console.log(res);
          this.billList = res.data.data;
        } catch (error) {
          console.log(error);
        }
      },
      // 添加账单
      async addBill() {
        // 判断是否输入了消费名称
        if (!this.billName) return alert('请输入消费名称');
        // 判断是否输入了消费价格和是否为数字
        if (!this.billPrice || isNaN(this.billPrice)) return alert('请输入正确的消费价格');

        try {
          const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
            creator,
            name: this.billName,
            price: this.billPrice,
          });
          console.log(res);
          this.billName = '';
          this.billPrice = '';
          this.renderBillList();
        } catch (error) {
          console.log(error);
        }
      },
    },
    mounted() {
      this.renderBillList();
    },
    computed: {
      // 计算总金额
      totalPrice() {
        return this.billList.reduce((sum, item) => sum + item.price, 0);
      },
    },
  });
</script>
html
<div id="app">
  <div class="contain">
    <!-- 左侧列表 -->
    <div class="list-box">
      <!-- 添加资产 -->
      <form class="my-form">
        <input v-model.trim="billName" type="text" class="form-control" placeholder="消费名称" />
        <input v-model.number="billPrice" type="text" class="form-control" placeholder="消费价格" />
        <button @click="addBill" type="button" class="btn btn-primary">添加账单</button>
      </form>

      <table class="table table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>消费名称</th>
            <th>消费价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <!-- 使用 v-for 遍历 billList -->
          <tr v-for="(item, index) in billList" :key="item.id">
            <td>{{index+1}}</td>
            <td>{{item.name}}</td>
            <td :class="{red: item.price > 500}">{{item.price.toFixed(2)}}</td>
            <td><a @click.prevent="delBill(item.id)" href="javascript:;">删除</a></td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
            <td colspan="4">消费总计:{{totalPrice.toFixed(2)}} </td>
          </tr>
        </tfoot>
      </table>
    </div>

    <!-- 右侧图表 -->
    <div class="echarts-box" id="main"></div>
  </div>
</div>
<script src="./js/echarts.min.js"></script>
<script src="./js/vue.js"></script>
<script src="./js/axios.min.js"></script>
<script>
  const creator = 'Doraemon';
  const app = new Vue({
    el: '#app',
    data: {
      // 帐单列表数据
      billList: [],
      // 消费名称
      billName: '',
      // 消费价格
      billPrice: '',
    },
    methods: {
      // 获取帐单列表数据
      async renderBillList() {
        try {
          const res = await axios.get(`https://applet-base-api-t.itheima.net/bill?creator=${creator}`);
          console.log(res);
          this.billList = res.data.data;
        } catch (error) {
          console.log(error);
        }
      },
      // 添加账单
      async addBill() {
        // 判断是否输入了消费名称
        if (!this.billName) return alert('请输入消费名称');
        // 判断是否输入了消费价格和是否为数字
        if (!this.billPrice || isNaN(this.billPrice)) return alert('请输入正确的消费价格');

        try {
          const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
            creator,
            name: this.billName,
            price: this.billPrice,
          });
          console.log(res);
          this.billName = '';
          this.billPrice = '';
          this.renderBillList();
        } catch (error) {
          console.log(error);
        }
      },
      // 删除账单
      async delBill(id) {
        try {
          const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`);
          console.log(`删除账单:${id}`, res);
          this.renderBillList();
        } catch (error) {
          console.log(error);
        }
      },
    },
    mounted() {
      this.renderBillList();
    },
    computed: {
      // 计算总金额
      totalPrice() {
        return this.billList.reduce((sum, item) => sum + item.price, 0);
      },
    },
  });
</script>
html
<div id="app">
  <div class="contain">
    <!-- 左侧列表 -->
    <div class="list-box">
      <!-- 添加资产 -->
      <form class="my-form">
        <input v-model.trim="billName" type="text" class="form-control" placeholder="消费名称" />
        <input v-model.number="billPrice" type="text" class="form-control" placeholder="消费价格" />
        <button @click="addBill" type="button" class="btn btn-primary">添加账单</button>
      </form>

      <table class="table table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>消费名称</th>
            <th>消费价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <!-- 使用 v-for 遍历 billList -->
          <tr v-for="(item, index) in billList" :key="item.id">
            <td>{{index+1}}</td>
            <td>{{item.name}}</td>
            <td :class="{red: item.price > 500}">{{item.price.toFixed(2)}}</td>
            <td><a @click.prevent="delBill(item.id)" href="javascript:;">删除</a></td>
          </tr>
        </tbody>
        <tfoot>
          <tr>
            <td colspan="4">消费总计:{{totalPrice.toFixed(2)}} </td>
          </tr>
        </tfoot>
      </table>
    </div>

    <!-- 右侧图表 -->
    <div class="echarts-box" id="main"></div>
  </div>
</div>
<script src="./js/echarts.min.js"></script>
<script src="./js/vue.js"></script>
<script src="./js/axios.min.js"></script>
<script>
  const creator = 'Doraemon';
  const app = new Vue({
    el: '#app',
    data: {
      // 帐单列表数据
      billList: [],
      // 消费名称
      billName: '',
      // 消费价格
      billPrice: '',
    },
    methods: {
      // 获取帐单列表数据
      async renderBillList() {
        try {
          const res = await axios.get(`https://applet-base-api-t.itheima.net/bill?creator=${creator}`);
          console.log(res);
          this.billList = res.data.data;
        } catch (error) {
          console.log(error);
        }

        // 饼图数据动态渲染
        this.myChart.setOption({
          series: [
            {
              data: this.billList.map(item => ({ value: item.price, name: item.name })),
            },
          ],
        });
      },
      // 添加账单
      async addBill() {
        // 判断是否输入了消费名称
        if (!this.billName) return alert('请输入消费名称');
        // 判断是否输入了消费价格和是否为数字
        if (!this.billPrice || isNaN(this.billPrice)) return alert('请输入正确的消费价格');

        try {
          const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
            creator,
            name: this.billName,
            price: this.billPrice,
          });
          console.log(res);
          this.billName = '';
          this.billPrice = '';
          this.renderBillList();
        } catch (error) {
          console.log(error);
        }
      },
      // 删除账单
      async delBill(id) {
        try {
          const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`);
          console.log(`删除账单:${id}`, res);
          this.renderBillList();
        } catch (error) {
          console.log(error);
        }
      },
    },
    mounted() {
      this.renderBillList();

      // 饼图渲染
      // 基于准备好的 dom,初始化 echarts 实例
      this.myChart = echarts.init(document.querySelector('#main'));
      // 指定图表的配置项和数据
      const option = {
        // 标题
        title: {
          text: '消费统计',
          subtext: '小黑记账清单',
        },
        // 提示框
        tooltip: {
          trigger: 'item',
          formatter: '{a} <br/>{b} : {c} ({d}%)',
        },
        // 图例
        legend: {
          // orient: 'vertical', // 垂直排列
          // left: 'left',
          top: 'bottom'
        },
        series: [
          {
            name: '消费统计',
            type: 'pie', // 饼图
            radius: [50, 100], // 半径
            center: ['50%', '50%'], // 圆心位置
            // roseType: 'area', // 南丁格尔图
            itemStyle: { // 饼图样式
              borderRadius: 8 // 圆角
            },
            data: [
              // 数据动态渲染
              // { value: 0, name: '餐饮' },
              // { value: 0, name: '交通' },
            ],
            emphasis: { // 高亮样式
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)',
              },
            },
          },
        ],
      };
      // 使用刚指定的配置项和数据显示图表
      this.myChart.setOption(option);
    },
    computed: {
      // 计算总金额
      totalPrice() {
        return this.billList.reduce((sum, item) => sum + item.price, 0);
      },
    },
  });
</script>

案例总结

2e400494-49d0-46bf-b7f4-2c07a4ab8330