二七(vue2-03)、生命周期四个阶段及八个钩子、工程化开发和脚手架、组件注册、拆分组件

发布于:2024-12-20 ⋅ 阅读:(16) ⋅ 点赞:(0)

1. 生命周期

1.1 生命周期四个阶段

<!-- 
  Vue生命周期:一个Vue实例从 创建 到 销毁 的整个过程。
  生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
    1.创建阶段:创建响应式数据
    2.挂载阶段:渲染模板
    3.更新阶段:修改数据,更新视图
    4.销毁阶段:销毁Vue实例
-->

1.2 生命周期钩子

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div id="app">
      <h3>{{ title }}</h3>
      <div>
        <button @click="count--">-</button>
        <span>{{ count }}</span>
        <button @click="count++">+</button>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

    <!-- 
      Vue生命周期钩子
      Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】,
      让开发者可以在【特定阶段】运行自己的代码
    -->
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          count: 100,
          title: "计数器",
        },

        beforeCreate() {
          console.log("beforeCreate", this.count);
          // beforeCreate undefined
        },
        created() {
          console.log("created", this.count);
          // created 100
        },
        beforeMount() {
          console.log("beforeMount", document.querySelector("h3"));
          // beforeMount <h3>​{{ title }}​</h3>​
        },
        mounted() {
          console.log("mounted", document.querySelector("h3"));
          // mounted <h3>​计数器​</h3>​
        },
        beforeUpdate() {
          console.log(
            "beforeUpdata",
            this.count,
            document.querySelector("span").innerHTML
          );
          // beforeUpdata 101 100
        },
        updated() {
          console.log(
            "updated",
            this.count,
            document.querySelector("span").innerHTML
          );
          // updated 101 101
        },

        // app.$destroy()
        beforeDestroy() {
          console.log("beforeDestory");
        },
        destroyed() {
          console.log("destroyed");
        },
      });
    </script>
  </body>
</html>

1.3 生命周期案例

1.3.1 created应用 - 新闻列表

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        list-style: none;
      }

      .news {
        display: flex;
        height: 120px;
        width: 600px;
        margin: 0 auto;
        padding: 20px 0;
        cursor: pointer;
      }

      .news .left {
        flex: 1;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        padding-right: 10px;
      }

      .news .left .title {
        font-size: 20px;
      }

      .news .left .info {
        color: #999999;
      }

      .news .left .info span {
        margin-right: 20px;
      }

      .news .right {
        width: 160px;
        height: 120px;
      }

      .news .right img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    </style>
  </head>

  <body>
    <div id="app">
      <ul>
        <li class="news" v-for="item in list" :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="" />
          </div>
        </li>
      </ul>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
      // 接口地址:http://hmajax.itheima.net/api/news
      // 请求方式:get
      const app = new Vue({
        el: "#app",
        data: {
          list: [],
        },

        // created 数据准备好了,可以开始发送初始化渲染请求。
        async created() {
          const res = await axios.get("http://hmajax.itheima.net/api/news");
          // console.log(res.data.data)
          this.list = res.data.data;
        },
      });
    </script>
  </body>
</html>

1.3.2 mounted应用 - 输入框获取焦点

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>示例-获取焦点</title>
    <!-- 初始化样式 -->
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/reset.css@2.0.2/reset.min.css"
    />
    <!-- 核心样式 -->
    <style>
      html,
      body {
        height: 100%;
      }

      .search-container {
        position: absolute;
        top: 30%;
        left: 50%;
        transform: translate(-50%, -50%);
        text-align: center;
      }

      .search-container .search-box {
        display: flex;
      }

      .search-container img {
        margin-bottom: 30px;
      }

      .search-container .search-box input {
        width: 512px;
        height: 16px;
        padding: 12px 16px;
        font-size: 16px;
        margin: 0;
        vertical-align: top;
        outline: 0;
        box-shadow: none;
        border-radius: 10px 0 0 10px;
        border: 2px solid #c4c7ce;
        background: #fff;
        color: #222;
        overflow: hidden;
        box-sizing: content-box;
        -webkit-tap-highlight-color: transparent;
      }

      .search-container .search-box button {
        cursor: pointer;
        width: 112px;
        height: 44px;
        line-height: 41px;
        line-height: 42px;
        background-color: #ad2a27;
        border-radius: 0 10px 10px 0;
        font-size: 17px;
        box-shadow: none;
        font-weight: 400;
        border: 0;
        outline: 0;
        letter-spacing: normal;
        color: white;
      }

      body {
        background: no-repeat center / cover;
        background-color: #edf0f5;
      }
    </style>
  </head>

  <body>
    <div class="container" id="app">
      <div class="search-container">
        <img src="https://www.itheima.com/images/logo.png" alt="" />
        <div class="search-box">
          <input type="text" v-model="words" id="inp" />
          <button>搜索一下</button>
        </div>
      </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
      const app = new Vue({
        el: "#app",
        data: {
          words: "",
        },

        // mounted 模板渲染完成,可以开始操作DOM了。
        mounted() {
          document.querySelector("#inp").focus();
        },
      });
    </script>
  </body>
</html>

2. 综合案例 - 小黑记账清单

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!-- CSS only -->
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
    />
    <style>
      .red {
        color: red !important;
      }

      .search {
        width: 300px;
        margin: 20px 0;
      }

      .my-form {
        display: flex;
        margin: 20px 0;
      }

      .my-form input {
        flex: 1;
        margin-right: 20px;
      }

      .table > :not(:first-child) {
        border-top: none;
      }

      .contain {
        display: flex;
        padding: 10px;
      }

      .list-box {
        flex: 1;
        padding: 0 30px;
      }

      .list-box a {
        text-decoration: none;
      }

      .echarts-box {
        width: 600px;
        height: 400px;
        padding: 30px;
        margin: 0 auto;
        border: 1px solid #ccc;
      }

      tfoot {
        font-weight: bold;
      }

      @media screen and (max-width: 1000px) {
        .contain {
          flex-wrap: wrap;
        }

        .list-box {
          width: 100%;
        }

        .echarts-box {
          margin-top: 30px;
        }
      }
    </style>
  </head>

  <body>
    <div id="app">
      <div class="contain">
        <!-- 左侧列表 -->
        <div class="list-box">
          <!-- 添加资产 -->
          <form class="my-form">
            <input
              type="text"
              class="form-control"
              placeholder="消费名称"
              v-model.trim="billName"
            />
            <input
              type="text"
              class="form-control"
              placeholder="消费价格"
              v-model.trim.number="billPrice"
            />
            <button type="button" class="btn btn-primary" @click="add">
              添加账单
            </button>
          </form>

          <table class="table table-hover">
            <thead>
              <tr>
                <th>编号</th>
                <th>消费名称</th>
                <th>消费价格</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              <tr v-for="(item,index) in list" :key="item.id">
                <td>{{index+1}}</td>
                <td>{{item.name}}</td>
                <td>{{item.price}}</td>
                <td><a href="javascript:;" @click="del(item.id)">删除</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">消费总计: {{totalPrice}}</td>
              </tr>
            </tfoot>
          </table>
        </div>

        <!-- 右侧图表 -->
        <div class="echarts-box" id="main"></div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/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: {
          list: [],
          creator: "caihaili",
          billName: "",
          billPrice: "",
        },
        created() {
          /* const res = await axios.get('https://applet-base-api-t.itheima.net/bill', { params: { creator: this.creator } })
        // console.log(res.data.data)
        this.list = res.data.data */
          this.render();
        },
        mounted() {
          this.mychart = echarts.init(document.querySelector("#main"));
          this.mychart.setOption({
            title: {
              text: "消费账单列表",
              // subtext: 'Fake Data',
              left: "center",
            },
            tooltip: {
              trigger: "item",
            },
            legend: {
              orient: "vertical",
              left: "left",
            },
            series: [
              {
                name: "消费账单",
                type: "pie",
                radius: "50%",
                data: [
                  { value: 1048, name: "Search Engine" },
                  { value: 735, name: "Direct" },
                  { value: 580, name: "Email" },
                  { value: 484, name: "Union Ads" },
                  { value: 300, name: "Video Ads" },
                ],
                emphasis: {
                  itemStyle: {
                    shadowBlur: 10,
                    shadowOffsetX: 0,
                    shadowColor: "rgba(0, 0, 0, 0.5)",
                  },
                },
              },
            ],
          });
        },

        methods: {
          async render() {
            const res = await axios.get(
              "https://applet-base-api-t.itheima.net/bill",
              { params: { creator: this.creator } }
            );
            // console.log(res.data.data[1].price)
            this.list = res.data.data;

            this.mychart.setOption({
              series: [
                {
                  /* data: [
                  { value: 1048, name: 'Search Engine' },
                  { value: 735, name: 'Direct' },
                  { value: 580, name: 'Email' },
                  { value: 484, name: 'Union Ads' },
                  { value: 300, name: 'Video Ads' }
                ] */
                  data: this.list.map((item) => ({
                    value: item.price,
                    name: item.name,
                  })),
                },
              ],
            });
          },

          async add() {
            /* this.list.unshift({
            id: +new Date(),
            name: this.billName,
            price: this.billPrice,
          }) */
            if (this.billName === "" || this.billPrice === "") {
              alert("内容不能为空");
              return;
            }
            // axios简写时, post方法不用写data{}, 直接写键对值数据
            await axios.post("https://applet-base-api-t.itheima.net/bill", {
              // id: +new Date(),
              name: this.billName,
              price: this.billPrice,
              creator: this.creator,
            });
            this.render();
            this.billName = "";
            this.billPrice = "";
          },

          async del(id) {
            await axios.delete(
              `https://applet-base-api-t.itheima.net/bill/${id}`
            );
            this.render();
          },
        },

        computed: {
          totalPrice() {
            return this.list.reduce((sum, item) => {
              return (sum += item.price);
            }, 0);
          },
        },
      });
    </script>
  </body>
</html>

3. 工程化开发入门

3.1 工程化开发和脚手架

/* 
  1. 开发Vue的两种方式
    - 核心包传统开发模式:基于html / css / js 文件,直接引入核心包,开发 Vue。
    - 工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue。
  2. 工程化开发模式优点:
    提高编码效率,比如使用JS新语法、Less/Sass、Typescript等通过webpack都可以编译成浏览器识别的ES3/ES5/CSS等

  3. 脚手架Vue CLI
    Vue CLI 是Vue官方提供的一个全局命令工具
    可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】

  4. 使用步骤:
    1. 全局安装(只需安装一次即可) yarn global add @vue/cli 或者 npm i @vue/cli -g
    2. 查看vue/cli版本:vue --version
    3. 创建项目架子:vue create project-name(项目名不能使用中文)
    4. 启动项目:yarn serve 或者 npm run serve(命令不固定,找package.json)
*/

3.2 项目运行流程

3.3 组件化

3.4 组件注册

<template>
  <!-- <vue 回车可生成框架 -->
  <!-- template 只允许有一个根元素 -->
  <div class="app">
    <!-- 3. 使用组件 组件名+Tab 补充尖括号 -->
    <HmHeader></HmHeader>
    <HmMain></HmMain>
  </div>
</template>

<script>
// 1. 导入
import HmHeader from "./components/HmHeader.vue";
import HmMain from "./components/HmMain.vue";

export default {
  // 2. 注册组件(局部)
  components: {
    HmHeader,
    HmMain,
  },
};
</script>

<style>
.app {
  width: 400px;
  height: 600px;
  background-color: blueviolet;
  padding: 10px;
  box-sizing: border-box;
  margin: 0 auto;
}
</style>

4. 综合案例 - 小兔鲜首页 - 拆分组件

Alt+Shift 多光标,Shift+左右箭头 多光标选中

5. 作业

5.1 BOSS直聘薪资分析-综合实战

5.2 Saas系统布局-变形题

5.3 重构百度云盘文件列表-二次开发