vue重修003

版权声明

  • 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用,并非商业用途。
  • 我在整理学习笔记的过程中尽力确保准确性,但无法保证内容的完整性和时效性。本博客的内容可能会随着时间的推移而过时或需要更新。
  • 若您是黑马程序员或相关权利人,如有任何侵犯版权的地方,请您及时联系我,我将立即予以删除或进行必要的修改。
  • 对于其他读者,请在阅读本博客内容时保持遵守相关法律法规和道德准则,谨慎参考,并自行承担因此产生的风险和责任。

day03

一、今日目标

1.生命周期

  1. 生命周期介绍
  2. 生命周期的四个阶段
  3. 生命周期钩子
  4. 声明周期案例

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

  1. 列表渲染
  2. 添加/删除
  3. 饼图渲染

3.工程化开发入门

  1. 工程化开发和脚手架
  2. 项目运行流程
  3. 组件化
  4. 组件注册

4.综合案例-小兔仙首页

  1. 拆分模块-局部注册
  2. 结构样式完善
  3. 拆分组件 – 全局注册

二、Vue生命周期

思考:什么时候可以发送初始化渲染请求?(越早越好)什么时候可以开始操作dom?(至少dom得渲染出来)

Vue生命周期:就是一个Vue实例从创建 到 销毁 的整个过程。

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

1.创建阶段:创建响应式数据

2.挂载阶段:渲染模板

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

4.销毁阶段:销毁Vue实例

在这里插入图片描述

三、Vue生命周期钩子

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

在这里插入图片描述

<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>
  <script>
    const app = new Vue({
      
      
      el: '#app',
      data: {
      
      
        count: 100,
        title: '计数器'
      },
      // 1. 创建阶段(准备数据)
      beforeCreate () {
      
      
        console.log('beforeCreate 响应式数据准备好之前', this.count)
      },
      created () {
      
      
        console.log('created 响应式数据准备好之后', this.count)
        // this.数据名 = 请求回来的数据
        // 可以开始发送初始化渲染的请求了
      },

      // 2. 挂载阶段(渲染模板)
      beforeMount () {
      
      
        console.log('beforeMount 模板渲染之前', document.querySelector('h3').innerHTML)
      },
      mounted () {
      
      
        console.log('mounted 模板渲染之后', document.querySelector('h3').innerHTML)
        // 可以开始操作dom了
      },

      // 3. 更新阶段(修改数据 → 更新视图)
      beforeUpdate () {
      
      
        console.log('beforeUpdate 数据修改了,视图还没更新', document.querySelector('span').innerHTML)
      },
      updated () {
      
      
        console.log('updated 数据修改了,视图已经更新', document.querySelector('span').innerHTML)
      },

      // 4. 卸载阶段
      beforeDestroy () {
      
      
        console.log('beforeDestroy, 卸载前')
        console.log('清除掉一些Vue以外的资源占用,定时器,延时器...')
      },
      destroyed () {
      
      
        console.log('destroyed,卸载后')
      }
    })
  </script>

在这里插入图片描述

四、生命周期钩子小案例

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 v-for="(item, index) in list" :key="item.id" class="news">
        <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: []
      },
      async created () {
      
      
        // 1. 发送请求获取数据
        const res = await axios.get('http://hmajax.itheima.net/api/news')
        // 2. 更新到 list 中,用于页面渲染 v-for
        this.list = res.data.data
      }
    })
  </script>
</body>
</html>

在这里插入图片描述

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/[email protected]/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="./vue.js"></script>
<script>
    const app = new Vue({
      
      
        el: '#app',
        data: {
      
      
            words: ''
        },
        mounted() {
      
      
            document.querySelector('#inp').focus()
        }
    })
</script>
</body>
</html>

五、案例-小黑记账清单

1.需求图示:

在这里插入图片描述

2.需求分析

1.基本渲染

2.添加功能

3.删除功能

4.饼图渲染

3.思路分析

在这里插入图片描述

4.代码

 <!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/[email protected]/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 v-model.trim="name" type="text" class="form-control" placeholder="消费名称" />
            <input v-model.number="price" type="text" class="form-control" placeholder="消费价格" />
            <button @click="add" 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 v-for="(item,index) in list" :key="item.id" >
                <td>{
   
   {index}}</td>
                <td>{
   
   {item.name}}</td>
                <td class="{red: item.price > 500}">{
   
   {item.price.toFixed(2)}}</td>
                <td><a href="javascript:;" @click="del(item.id)">删除</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="../echarts.min.js"></script>
    <script src="../vue.js"></script>
    <script src="../axios.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:[],
          name: '',
          price: ''
        },
        computed: {
      
      
          totalPrice () {
      
      
            return this.list.reduce((sum,item) => sum + item.price,0)
          }
        },
        mounted() {
      
      
          this.myChart=echarts.init(document.querySelector('#main'))
          this.myChart.setOption({
      
      
            // 大标题
            title: {
      
      
              text: '消费账单列表',
              left: 'center'
            },
            // 提示框
            tooltip: {
      
      
              trigger: 'item'
            },
            // 图例
            legend: {
      
      
              orient: 'vertical',
              left: 'left'
            },
            // 数据项
            series: [
              {
      
      
                name: '消费账单',
                type: 'pie',
                radius: '50%', // 半径
                data: [

                ],
                emphasis: {
      
      
                  itemStyle: {
      
      
                    shadowBlur: 10,
                    shadowOffsetX: 0,
                    shadowColor: 'rgba(0, 0, 0, 0.5)'
                  }
                }
              }
            ]
          })
        },
       async created() {
      
      
          this.getList()
        },
        methods:{
      
      
          async add() {
      
      
            if (!this.name) {
      
      
              alert('请输入消费名称')
              return
            }
            if (typeof this.price !== 'number') {
      
      
              alert('请输入正确的消费价格')
              return
            }
            const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
      
      
              creator: '小白',
              name: this.name,
              price: this.price
            })
            //重新渲染
            this.getList()

            this.name = ''
            this.price = ''
          },
          async getList() {
      
      
            const res=await axios.get('https://applet-base-api-t.itheima.net/bill',{
      
      
              params:{
      
      
                creator: '小白'
              }
            })
            this.list=res.data.data
            this.myChart.setOption({
      
      
              series: [
                {
      
      
                  data: this.list.map(item=>({
      
      value: item.price , name: item.name}))
                }
              ]
            })
          },
          async del(id) {
      
      
            const res=await axios.delete(`https://applet-base-api-t.itheima.net/bill/${ 
        id}`)
            //重新渲染
            this.getList()
          }
        }
      })
    </script>
  </body>
</html>

在这里插入图片描述

六、工程化开发和脚手架

1.开发Vue的两种方式

  • 核心包传统开发模式:基于html / css / js 文件,直接引入核心包,开发 Vue。
  • 工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue。

在这里插入图片描述

工程化开发模式优点:

提高编码效率,比如使用JS新语法、Less/Sass、Typescript等通过webpack都可以编译成浏览器识别的ES3/ES5/CSS等

工程化开发模式问题:

  • webpack配置不简单
  • 雷同的基础配置
  • 缺乏统一的标准

为了解决以上问题,所以我们需要一个工具,生成标准化的配置

2.脚手架Vue CLI

基本介绍:

Vue CLI 是Vue官方提供的一个全局命令工具

可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】

好处:
  1. 开箱即用,零配置
  2. 内置babel等工具
  3. 标准化的webpack配置
使用步骤:
  1. 全局安装(只需安装一次即可) npm i @vue/cli -g
  2. 查看vue/cli版本: vue --version
  3. 创建项目架子:`vue create project-name(项目名不能使用中文)
  4. 启动项目:npm run serve(命令不固定,找package.json)

七、项目目录介绍和运行流程

1.项目目录介绍

在这里插入图片描述

虽然脚手架中的文件有很多,目前咱们只需关注三个文件即可

  1. main.js 入口文件
// 文件核心作用:导入App.vue,基于App.vue创建结构渲染index.html
// 1. 导入 Vue 核心包
import Vue from 'vue'

// 2. 导入 App.vue 根组件
import App from './App.vue'

// 提示:当前处于什么环境 (生产环境 / 开发环境)
Vue.config.productionTip = false

// 3. Vue实例化,提供render方法 → 基于App.vue创建结构渲染index.html
new Vue({
    
    
  // el: '#app', 作用:和$mount('选择器')作用一致,用于指定Vue所管理容器
  // render: h => h(App),
  render: (createElement) => {
    
    
    // 基于App创建元素结构
    return createElement(App)
  }
}).$mount('#app')
  1. App.vue App根组件
<template>
  <div class="App">
    <div class="box" @click="fn"></div>
  </div>
</template>

<script>
// 导出的是当前组件的配置项
// 里面可以提供 data(特殊) methods computed watch 生命周期八大钩子
export default {
      
      
  created () {
      
      
    console.log('我是created')
  },
  methods: {
      
      
    fn () {
      
      
      alert('你好')
    }
  }
}
</script>

<style lang="less">
/* 让style支持less
   1. 给style加上 lang="less"
   2. 安装依赖包 less less-loader
      yarn add less less-loader -D (开发依赖)
*/
.App {
      
      
  width: 400px;
  height: 400px;
  background-color: pink;
  .box {
      
      
    width: 100px;
    height: 100px;
    background-color: skyblue;
  }
}
</style>
  1. index.html 模板文件

    <!DOCTYPE html>
    <html lang="">
      <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">
        <link rel="icon" href="<%= BASE_URL %>favicon.ico">
        <title><%= htmlWebpackPlugin.options.title %></title>
      </head>
      <body>
        <!-- 兼容:给不支持js的浏览器一个提示 -->
        <noscript>
          <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
        </noscript>
    
        <!-- Vue所管理的容器:将来创建结构动态渲染这个容器 -->
        <div id="app">
          <!-- 工程化开发模式中:这里不再直接编写模板语法,通过 App.vue 提供结构渲染 -->
        </div>
    
        <!-- built files will be auto injected -->
      </body>
    </html>
    

2.运行流程

在这里插入图片描述

3. 项目创建

  1. 使用vue create name

在这里插入图片描述
在这里插入图片描述

八、组件化开发

​ 组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为。

​ 好处:便于维护,利于复用 → 提升开发效率。

​ 组件分类:普通组件、根组件。

​ 比如:下面这个页面,可以把所有的代码都写在一个页面中,但是这样显得代码比较混乱,难易维护。咱们可以按模块进行组件划分

在这里插入图片描述

九、根组件 App.vue

1.根组件介绍

整个应用最上层的组件,包裹所有普通小组件

在这里插入图片描述

2.组件是由三部分构成

  • 语法高亮插件

30724024159.png?origin_url=assets%2F1682169264266.png&pos_id=img-HXBQVboH-1695533416796)

  • 三部分构成

    • template:结构 (有且只能一个根元素)
    • script: js逻辑
    • style: 样式 (可支持less,需要装包)
  • 让组件支持less

    (1) style标签,lang="less"开启less功能

    (2) 装包: yarn add less less-loader -D 或者npm i less less-loader -D

3.总结

App组件三大部分:结构、行为、样式

十、普通组件的注册使用-局部注册

  1. 特点:只能在注册的组件内使用

  2. 步骤:

    1. 创建.vue文件(三个组成部分)
    2. 在使用的组件内先导入再注册,最后使用
    3. 使用方式:当成html标签使用即可 <组件名></组件名>

4.注意:组件名规范 —> 大驼峰命名法, 如 HmHeader

5.语法:

在这里插入图片描述

// 导入需要注册的组件
import 组件对象 from '.vue文件路径'
import HmHeader from './components/HmHeader'

export default {
    
      // 局部注册
  components: {
    
    
   '组件名': 组件对象,
    HmHeader:HmHeaer,
    HmHeader
  }
}

6.练习

在App组件中,完成以下练习。在App.vue中使用组件的方式完成下面布局

在这里插入图片描述

<template>
  <div class="hm-header">
    我是hm-header
  </div>
</template>

<script>
export default {
      
      

}
</script>

<style>
.hm-header {
      
      
  height: 100px;
  line-height: 100px;
  text-align: center;
  font-size: 30px;
  background-color: #8064a2;
  color: white;
}
</style>
<template>
  <div class="hm-main">
    我是hm-main
  </div>
</template>

<script>
export default {
      
      

}
</script>

<style>
.hm-main {
      
      
  height: 400px;
  line-height: 400px;
  text-align: center;
  font-size: 30px;
  background-color: #f79646;
  color: white;
  margin: 20px 0;
}
</style>
<template>
  <div class="hm-footer">
    我是hm-footer
  </div>
</template>

<script>
export default {
      
      

}
</script>

<style>
.hm-footer {
      
      
  height: 100px;
  line-height: 100px;
  text-align: center;
  font-size: 30px;
  background-color: #4f81bd;
  color: white;
}
</style>
<template>
  <div class="App">
    <!-- 头部组件 -->
    <HmHeader></HmHeader>
    <!-- 主体组件 -->
    <HmMain></HmMain>
    <!-- 底部组件 -->
    <HmFooter></HmFooter>

    <!-- 如果 HmFooter + tab 出不来 → 需要配置 vscode
         设置中搜索 trigger on tab → 勾上
    -->
  </div>
</template>

<script>
import HmHeader from './components/HmHeader.vue'
import HmMain from './components/HmMain.vue'
import HmFooter from './components/HmFooter.vue'
export default {
      
      
  components: {
      
      
    // '组件名': 组件对象
    HmHeader: HmHeader,
    HmMain,
    HmFooter
  }
}
</script>

<style>
.App {
      
      
  width: 600px;
  height: 700px;
  background-color: #87ceeb;
  margin: 0 auto;
  padding: 20px;
}
</style>

十一、普通组件的注册使用-全局注册

1.特点:

全局注册的组件,在项目的任何组件中都能使用

2.步骤

  1. 创建.vue组件(三个组成部分)
  2. main.js中进行全局注册

3.使用方式

当成HTML标签直接使用

<组件名></组件名>

4.注意

组件名规范 —> 大驼峰命名法, 如 HmHeader

5.语法

Vue.component(‘组件名’, 组件对象)

例:

// 导入需要全局注册的组件
import HmButton from './components/HmButton'
Vue.component('HmButton', HmButton)

6.练习

在以下3个局部组件中是展示一个通用按钮

在这里插入图片描述

<template>
  <button class="hm-button">通用按钮</button>
</template>

<script>
export default {
      
      

}
</script>

<style>
.hm-button {
      
      
  height: 50px;
  line-height: 50px;
  padding: 0 20px;
  background-color: #3bae56;
  border-radius: 5px;
  color: white;
  border: none;
  vertical-align: middle;
  cursor: pointer;
}
</style>

十二、综合案例

1.小兔仙首页启动项目演示

2.小兔仙组件拆分示意图

在这里插入图片描述

3.开发思路

  1. 分析页面,按模块拆分组件,搭架子 (局部或全局注册)

  2. 根据设计图,编写组件 html 结构 css 样式 (已准备好)

  3. 拆分封装通用小组件 (局部或全局注册)

    将来 → 通过 js 动态渲染,实现功能

猜你喜欢

转载自blog.csdn.net/yang2330648064/article/details/133238587
003