当前位置:   article > 正文

WEB07Vue+Ajax

WEB07Vue+Ajax

1. Vue概述

Vue(读音 /vjuː/, 类似于 view),是一款用于构建用户界面渐进式的JavaScript框架(官方网站:https://cn.vuejs.org)。

在上面的这句话中呢,出现了三个词,分别是:构建用户界面、渐进式、框架。

1). 构建用户界面

构建用户界面是指,在Vue中,可以基于数据渲染出用户看到的界面。 那这句话什么意思呢?我们来举一个例子,比如将来服务器端返回给前端的原始数据呢,就是如下这个样子:

userList: [
    {"id": 1, "name": "谢逊", "image": "1.jpg", "gender": 1, "job": "班主任"},
    {"id": 2, "name": "韦一笑", "image": "2.jpg", "gender": 1, "job": "班主任"}
]

而上面的这些原始数据,用户是看不懂的。 而我们开发人员呢,可以使用Vue中提供的操作,将原始数据遍历、解析出来,从而渲染呈现出用户所能看懂的界面,如下所示:

那这个过程呢,就是基于数据渲染出用户看到的界面,也就是所谓的 构建用户界面。

2). 渐进式

渐进式中的渐进呢,字面意思就是 "循序渐进"。Vue生态中的语法呢是非常多的,比如声明式渲染、组件系统、客户端路由(VueRouter)、状态管理(Vuex、Pinia)、构建工具(Webpack、Vite)等等。

所谓渐进,指的是我们使用Vue框架呢,我们不需要把所有的组件、语法全部学习完毕才可以使用Vue。 而是,我们学习一点就可以使用一点了,比如:

  • 我们学习了声明式渲染,我们就可以使用Vue来构建用户界面了。

  • 我们再学习了组件系统,我们就可以使用Vue中的组件,从而来复用了。

  • 我们再学习了路由VueRouter,就可以使用Vue中的中的路由功能了。

也就是说,并不需要全部学习完毕就可以直接使用Vue进行开发,简化操作、提高效率了。 Vue是一个框架,但其实也是一个生态。

那由此呢,也就引出了Vue中两种常见的开发模式:

  1. 基于Vue提供的核心包,完成项目局部模块的改造了。

  2. 基于Vue提供的核心包、插件进行工程化开发,也就是做整站开发。

那上面的这两种Vue的使用形式,我们都会学习,今天我们先来学习第一种方式,就是使用Vue来完成局部模块改造。

3). 框架

  • 框架:就是一套完整的项目解决方案,用于快速构建项目 。这是我们接触的第一个框架,那在我们后面的学习中,我们还会学习很多的java语言中的框架,那通过这些框架呢,就可以来快速开发java项目,提高开发效率。

  • 优点:大大提升前端项目的开发效率 。

  • 缺点:需要理解记忆框架的使用规则 。(参照官网)

好,那我们知道了什么是Vue之后,接下来,就要正式进入Vue的学习,我们今天主要讲解以下几个方面:

  1. Vue快速入门

  2. Vue常用指令

  3. Ajax

  4. Vue生命周期

2. 快速入门

接下来我们通过一个vue的快速入门案例,来体验一下Vue开发,并掌握Vue的开发步骤 。那在这个入门程序中,我们就要完成刚才上面提到的,基于数据渲染出用户看到的页面,也就是数据驱动视图(这个视图指的就是页面的展示)操作。

2.1 需求

在入门程序中,最终我们需要将准备的数据 message 的值,基于Vue渲染展示在页面中,最终呈现的形式如下:

2.2 步骤

1). 准备工作:

  • 准备一个html文件,并在其中引入Vue模块 (参考官方文档,复制过来即可)【注意:模块化的js,引入时,需要设置 type="module"

  • 创建Vue程序的应用实例,控制视图的元素

  • 准备元素(div),交给Vue控制

这三步准备工作,是我们使用Vue时,都需要做的,是固定步骤。 这样我们就搭建好了一个基本的Vue的结构了。

2). 数据驱动视图:

  • 准备数据。 在创建Vue应用实例的时候,传入了一个js对象,在这个js对象中,我们要定义一个data方法,这个data方法的返回值就是Vue中的数据。

  • 通过插值表达式渲染页面。 插值表达式的写法:{{...}}

2.3 实现

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.  <title>Vue-快速入门</title>
  7. </head>
  8. <body>
  9.  <div id="app">
  10.   {{message}}
  11.  </div>
  12.  
  13.  <script type="module">
  14.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  15.    createApp({
  16.      data(){
  17.        return {
  18.          message: 'Hello Vue'
  19.       }
  20.     }
  21.   }).mount('#app')
  22.  </script>
  23. </body>
  24. </html>

在上述入门程序编写时,需要注意这么几点:

  • Vue中定义数据,必须通过data方法来定义,data方法返回值是一个对象,在这个对象中定义数据。

  • 插值表达式中编写的变量,一定是Vue中定义的数据,如果插值表达式中编写了一个变量,但是在Vue中未定义,将会报错 。

  • Vue应用实例接管的区域是 '#app',超出这个范围,就不受Vue控制了,所以vue的插值表达式,一定写在 <div id="app">...</div> 的里面 。

3. Vue指令

3.1 介绍

刚才通过一个快速入门程序,大家快速感受了一下Vue的开发,并明确了Vue的开发步骤。那接下来,我们要来学习的是Vue中的常用指令,通过Vue中的指令,就可以将原始的数据,根据不同的需求,渲染展示在界面中。

而在讲解Vue指令的时候呢,我们将会通过一个小案例来贯穿始终。 那就是用户列表渲染的案例,需求如下所示:

将Vue中定义的数据userList,渲染展示在视图的表格之中。 在原始数据中,性别gender如果为1,展示为"男";如果为2,展示为"女"。 在原始数据中,职位job如果为1,展示为"讲师";如果为2,展示为"班主任";如果为3,展示为"其他"。

而要想完成这个需求,就需要用到Vue中的一些常用指令,那接下来呢,我们就来介绍一下Vue中的常用指令。

指令:指的是HTML 标签上带有 v- 前缀的特殊属性,不同指令具有不同含义,可以实现不同的功能 。例如:v-if,v-for…

指令作用
v-for列表渲染,遍历容器的元素或者对象的属性
v-bind为HTML标签绑定属性值,如设置 href , css样式等
v-if/v-else-if/v-else条件性的渲染某元素,判定为true时渲染,否则不渲染
v-show根据条件展示某元素,区别在于切换的是display属性的值
v-model在表单元素上创建双向数据绑定
v-on为HTML标签绑定事件

3.2 v-for

3.2.1 介绍

作用:列表渲染,遍历容器的元素或者对象的属性

语法:v-for = "(item,index) in items"

参数:

  • items 为遍历的数组

  • item 为遍历出来的元素

  • index 为索引/下标,从0开始 ;可以省略,省略index语法: v-for = "item in items"

示例:

3.2.2 演示

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.  <title>v-for入门</title>
  7. </head>
  8. <body>
  9.  
  10.  <div id="app">
  11.    <p v-for="(name,index) in names">{{index + 1}}: {{name}}</p>
  12.  </div>
  13.  
  14.  <script type="module">
  15.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  16.    createApp({
  17.      data(){
  18.        return {
  19.          names: ['张无忌', '张三丰', '韦一笑', '殷天正']
  20.       }
  21.     }
  22.   }).mount('#app')
  23.  </script>
  24. </body>
  25. </html>

经过浏览器的解析渲染之后,展示出如下界面:

3.2.3 v-for的key

作用:给元素添加的唯一标识,便于vue进行列表项的正确排序复用

语法: v-for="(item,index) in items" :key="唯一值"

注意点:

  • key的值只能是字符串 或 数字类型

  • key的值必须具有唯一性

  • 推荐使用id作为key(唯一),不推荐使用index作为key(会变化,不对应)

写法:

提示:官方推荐在使用 v-for 时提供一个key属性,以遍可以追踪每个节点,提升渲染性能。

3.2.4 案例-列表渲染

v-for 指令的作用及语法我们清楚之后,那接下来,我们就来完成案例中的列表渲染。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.  <title>Vue3-案例1</title>
  8.  <style>
  9.    table,th,td {
  10.      border: 1px solid #000;
  11.      border-collapse: collapse;
  12.      line-height: 50px;
  13.      text-align: center;
  14.   }
  15.    #center,table {
  16.      width: 60%;
  17.      margin: auto;
  18.   }
  19.    #center {
  20.      margin-bottom: 20px;
  21.   }
  22.    img {
  23.      width: 50px;
  24.   }
  25.    input,select {
  26.      width: 17%;
  27.      padding: 10px;
  28.      margin-right: 30px;
  29.      border: 1px solid #ccc;
  30.      border-radius: 4px;
  31.   }
  32.    .btn {
  33.      background-color: #ccc;
  34.   }
  35.  </style>
  36. </head>
  37. <body>
  38.  <div id="app">
  39.    <div id="center">
  40.     姓名: <input type="text" name="name">
  41.     性别:
  42.      <select name="gender">
  43.        <option value="1"></option>
  44.        <option value="2"></option>
  45.      </select>
  46.     职位:
  47.      <select name="job">
  48.        <option value="1">讲师</option>
  49.        <option value="2">班主任</option>
  50.        <option value="3">其他</option>
  51.      </select>
  52.      <input class="btn" type="button" value="查询">
  53.    </div>
  54.    <table>
  55.      <tr>
  56.        <th>序号</th>
  57.        <th>姓名</th>
  58.        <th>头像</th>
  59.        <th>性别</th>
  60.        <th>职位</th>
  61.        <th>入职时间</th>
  62.        <th>更新时间</th>
  63.      </tr>
  64.  
  65.      <!-- 基于 v-for 指令循环遍历用户数据列表 -->
  66.      <tr v-for="(user, index) in userList" :key="user.id">
  67.        <td>{{index + 1}}</td>
  68.        <td>{{user.name}}</td>
  69.        <td> <img src="{{user.image}}"> </td>
  70.        <td>{{user.gender}}</td>
  71.        <td>{{user.job}}</td>
  72.        <td>{{user.entrydate}}</td>
  73.        <td>{{user.updatetime}}</td>
  74.      </tr>
  75.    </table>
  76.  </div>
  77.  <script type="module">
  78.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  79.    createApp({
  80.      data() {
  81.        return {
  82.          userList: [
  83.           {
  84.              "id": 1,
  85.              "name": "谢逊",
  86.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
  87.              "gender": 1,
  88.              "job": 1,
  89.              "entrydate": "2023-06-09",
  90.              "updatetime": "2023-07-01 00:00:00"
  91.           },
  92.           {
  93.              "id": 2,
  94.              "name": "韦一笑",
  95.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
  96.              "gender": 1,
  97.              "job": 1,
  98.              "entrydate": "2023-06-09",
  99.              "updatetime": "2023-07-01 00:00:00"
  100.           },
  101.           {
  102.              "id": 3,
  103.              "name": "黛绮丝",
  104.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/3.jpg",
  105.              "gender": 2,
  106.              "job": 2,
  107.              "entrydate": "2023-06-09",
  108.              "updatetime": "2023-07-01 00:00:00"
  109.           },
  110.           {
  111.              "id": 4,
  112.              "name": "殷天正",
  113.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
  114.              "gender": 1,
  115.              "job": 3,
  116.              "entrydate": "2023-06-09",
  117.              "updatetime": "2023-07-01 00:00:00"
  118.           }
  119.         ]
  120.       }
  121.     }
  122.   }).mount("#app");
  123.  </script>
  124. </body>
  125. </html>

浏览器打开此页面,最终浏览器中展示效果如下:

注意:插值表达式 {{...}} 只能用在标签内的文本区域,不能使用在标签的属性中,是无法解析的。所以上述的图片展示,是存在问题的(稍后解决)。

3.3 v-bind

3.3.1 介绍

作用:动态为HTML标签绑定属性值,如设置href,src,style样式等。

语法:v-bind:属性名="属性值"

简化::属性名="属性值"

注意:v-bind 所绑定的数据,必须在data中定义。

3.3.2 演示

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.  <title>v-bind入门</title>
  7. </head>
  8. <body>
  9.  
  10.  <div id="app">
  11.    <a v-bind:href="url">链接1</a> <br><br>
  12.    <a :href="url">链接2</a>
  13.  </div>
  14.  
  15.  <script type="module">
  16.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  17.    createApp({
  18.      data(){
  19.        return {
  20.          url: 'https://www.itcast.cn'
  21.       }
  22.     }
  23.   }).mount('#app')
  24.  </script>
  25. </body>
  26. </html>

通过上述代码,已经为a标签的href属性绑定上了url变量,如果数据 url 发生变化,v-bind绑定的属性也会自动发生变化。 我们可以F12打开浏览器的开发者工具,通过Vue插件,来修改Vue的数据url,我们会看到超链接的链接的地址会自动发生变化 。

3.3.3 案例-图片展示

接下来,我们就可以通过 v-bind 指令,来动态为 <img src=""> 的src属性绑定值,从而动态展示出图片内容。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.  <title>Vue3-案例1</title>
  8.  <style>
  9.    table,th,td {
  10.      border: 1px solid #000;
  11.      border-collapse: collapse;
  12.      line-height: 50px;
  13.      text-align: center;
  14.   }
  15.    #center,table {
  16.      width: 60%;
  17.      margin: auto;
  18.   }
  19.    #center {
  20.      margin-bottom: 20px;
  21.   }
  22.    img {
  23.      width: 50px;
  24.   }
  25.    input,select {
  26.      width: 17%;
  27.      padding: 10px;
  28.      margin-right: 30px;
  29.      border: 1px solid #ccc;
  30.      border-radius: 4px;
  31.   }
  32.    .btn {
  33.      background-color: #ccc;
  34.   }
  35.  </style>
  36. </head>
  37. <body>
  38.  <div id="app">
  39.    <div id="center">
  40.     姓名: <input type="text" name="name">
  41.     性别:
  42.      <select name="gender">
  43.        <option value="1"></option>
  44.        <option value="2"></option>
  45.      </select>
  46.     职位:
  47.      <select name="job">
  48.        <option value="1">讲师</option>
  49.        <option value="2">班主任</option>
  50.        <option value="3">其他</option>
  51.      </select>
  52.      <input class="btn" type="button" value="查询">
  53.    </div>
  54.    <table>
  55.      <tr>
  56.        <th>序号</th>
  57.        <th>姓名</th>
  58.        <th>头像</th>
  59.        <th>性别</th>
  60.        <th>职位</th>
  61.        <th>入职时间</th>
  62.        <th>更新时间</th>
  63.      </tr>
  64.      <tr v-for="(user, index) in userList" :key="user.id">
  65.        <td>{{index + 1}}</td>
  66.        <td>{{user.name}}</td>
  67.        <!-- 基于v-bind指令绑定src属性, 动态展示图片, 该指令简写为 : -->
  68.        <td> <img :src="user.image"> </td>
  69.        <td>{{user.gender}}</td>
  70.        <td>{{user.job}}</td>
  71.        <td>{{user.entrydate}}</td>
  72.        <td>{{user.updatetime}}</td>
  73.      </tr>
  74.    </table>
  75.  </div>
  76.  <script type="module">
  77.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  78.    createApp({
  79.      data() {
  80.        return {
  81.          userList: [
  82.           {
  83.              "id": 1,
  84.              "name": "谢逊",
  85.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
  86.              "gender": 1,
  87.              "job": 1,
  88.              "entrydate": "2023-06-09",
  89.              "updatetime": "2023-07-01 00:00:00"
  90.           },
  91.           {
  92.              "id": 2,
  93.              "name": "韦一笑",
  94.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
  95.              "gender": 1,
  96.              "job": 1,
  97.              "entrydate": "2023-06-09",
  98.              "updatetime": "2023-07-01 00:00:00"
  99.           },
  100.           {
  101.              "id": 3,
  102.              "name": "黛绮丝",
  103.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/3.jpg",
  104.              "gender": 2,
  105.              "job": 2,
  106.              "entrydate": "2023-06-09",
  107.              "updatetime": "2023-07-01 00:00:00"
  108.           },
  109.           {
  110.              "id": 4,
  111.              "name": "殷天正",
  112.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
  113.              "gender": 1,
  114.              "job": 3,
  115.              "entrydate": "2023-06-09",
  116.              "updatetime": "2023-07-01 00:00:00"
  117.           }
  118.         ]
  119.       }
  120.     },
  121.   }).mount("#app");
  122.  </script>
  123. </body>
  124. </html>

上述代码经过浏览器的解析之后,我们会看到图片就可以正常显示出来了。

注意:表格的基本内容,以及图片信息已经展示出来了,但是我们看到性别显示的确实1、2,那最终要展示出来的得是 男、女。

3.4 v-if & v-show

3.4.1 介绍

作用:这两类指令,都是用来控制元素的显示与隐藏的

v-if:

  • 语法:v-if="表达式",表达式值为 true,显示;false,隐藏

  • 原理:基于条件判断,来控制创建或移除元素节点(条件渲染)

  • 场景:要么显示,要么不显示,不频繁切换的场景

  • 其它:可以配合 v-else-if / v-else 进行链式调用条件判断

v-show:

  • 语法:v-show="表达式",表达式值为 true,显示;false,隐藏

  • 原理:基于CSS样式display来控制显示与隐藏

  • 场景:频繁切换显示隐藏的场景

注意:v-else-if必须出现在v-if之后,可以出现多个; v-else 必须出现在v-if/v-else-if之后 。

3.4.2 案例-性别职位展示

那接下来,我们就通过 v-ifv-show 指令来完成性别 、职位数据的展示。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.  <title>Vue3-案例1</title>
  8.  <style>
  9.    table,th,td {
  10.      border: 1px solid #000;
  11.      border-collapse: collapse;
  12.      line-height: 50px;
  13.      text-align: center;
  14.   }
  15.    #center,table {
  16.      width: 60%;
  17.      margin: auto;
  18.   }
  19.    #center {
  20.      margin-bottom: 20px;
  21.   }
  22.    img {
  23.      width: 50px;
  24.   }
  25.    input,select {
  26.      width: 17%;
  27.      padding: 10px;
  28.      margin-right: 30px;
  29.      border: 1px solid #ccc;
  30.      border-radius: 4px;
  31.   }
  32.    .btn {
  33.      background-color: #ccc;
  34.   }
  35.  </style>
  36. </head>
  37. <body>
  38.  <div id="app">
  39.    <div id="center">
  40.     姓名: <input type="text" name="name">
  41.     性别:
  42.      <select name="gender">
  43.        <option value="1"></option>
  44.        <option value="2"></option>
  45.      </select>
  46.     职位:
  47.      <select name="job">
  48.        <option value="1">讲师</option>
  49.        <option value="2">班主任</option>
  50.        <option value="3">其他</option>
  51.      </select>
  52.      <input class="btn" type="button" value="查询">
  53.    </div>
  54.    <table>
  55.      <tr>
  56.        <th>序号</th>
  57.        <th>姓名</th>
  58.        <th>头像</th>
  59.        <th>性别</th>
  60.        <th>职位</th>
  61.        <th>入职时间</th>
  62.        <th>更新时间</th>
  63.      </tr>
  64.      <tr v-for="(user, index) in userList" :key="user.id">
  65.        <td>{{index + 1}}</td>
  66.        <td>{{user.name}}</td>
  67.        <td> <img :src="user.image"> </td>
  68.        <td>
  69.          <!-- v-if 控制显示或隐藏 -->
  70.          <span v-if="user.gender == 1"></span>
  71.          <span v-else-if="user.gender == 2"></span>
  72.          <span v-else>其他</span>
  73.        </td>
  74.        <td>
  75.          <!-- v-show 控制显示或隐藏 -->
  76.          <span v-show="user.job == 1">讲师</span>
  77.          <span v-show="user.job == 2">班主任</span>
  78.          <span v-show="user.job == 3">其他</span>
  79.        </td>
  80.        <td>{{user.entrydate}}</td>
  81.        <td>{{user.updatetime}}</td>
  82.      </tr>
  83.    </table>
  84.  </div>
  85.  <script type="module">
  86.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  87.    createApp({
  88.      data() {
  89.        return {
  90.          userList: [
  91.           {
  92.              "id": 1,
  93.              "name": "谢逊",
  94.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
  95.              "gender": 1,
  96.              "job": 1,
  97.              "entrydate": "2023-06-09",
  98.              "updatetime": "2023-07-01 00:00:00"
  99.           },
  100.           {
  101.              "id": 2,
  102.              "name": "韦一笑",
  103.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
  104.              "gender": 1,
  105.              "job": 1,
  106.              "entrydate": "2023-06-09",
  107.              "updatetime": "2023-07-01 00:00:00"
  108.           },
  109.           {
  110.              "id": 3,
  111.              "name": "黛绮丝",
  112.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/3.jpg",
  113.              "gender": 2,
  114.              "job": 2,
  115.              "entrydate": "2023-06-09",
  116.              "updatetime": "2023-07-01 00:00:00"
  117.           },
  118.           {
  119.              "id": 4,
  120.              "name": "殷天正",
  121.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
  122.              "gender": 1,
  123.              "job": 3,
  124.              "entrydate": "2023-06-09",
  125.              "updatetime": "2023-07-01 00:00:00"
  126.           }
  127.         ]
  128.       }
  129.     },
  130.   }).mount("#app");
  131.  </script>
  132. </body>
  133. </html>

浏览器打开此页面后,经过浏览器的解析,数据可以正确的显示出来了 。

通过F12,打开浏览器的开发者工具,我们可以看到 v-if 控制元素的显示与隐藏时,如果条件不成立,压根就不会渲染对应的元素。 而通过 v-show 控制元素的显示或隐藏,基于 CSS 样式display来控制显示与隐藏。

所以,对于 v-if 适用于控制显示或隐藏不频繁的场景。 而 v-show 适用于显示与隐藏切换频繁的场景。

3.6 v-model

3.6.1 介绍

作用:在表单元素上使用,双向数据绑定。可以方便的 获取 或 设置 表单项数据

语法:v-model="变量名"

这里的双向数据绑定,是指 Vue中的数据变化,会影响视图中的数据展示。 视图中的输入的数据变化,也会影响Vue的数据模型 。

注意:v-model 中绑定的变量,必须在data中定义。

3.6.2 演示

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.  <title>v-model入门</title>
  7. </head>
  8. <body>
  9.  <div id="app">
  10.    <input type="text" v-model="name"> <br>
  11.   {{name}}
  12.  </div>
  13.  
  14.  <script type="module">
  15.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  16.    createApp({
  17.      data(){
  18.        return {
  19.          name: 'Vue'
  20.       }
  21.     }
  22.   }).mount('#app')
  23.  </script>
  24. </body>
  25. </html>

最终的效果如下: 视图中的数据变化,会影响Vue的数据模型。 Vue的属性模型变化,也会影响视图的展示 。

3.6.3 案例-获取搜索条件

接下来,我们要来完成案例中,搜索栏中用户输入的表单数据,用户输入表单项数据后,要将数据展示出来 。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.  <title>Vue3-案例1</title>
  8.  <style>
  9.    table,th,td {
  10.      border: 1px solid #000;
  11.      border-collapse: collapse;
  12.      line-height: 50px;
  13.      text-align: center;
  14.   }
  15.    #center,table {
  16.      width: 60%;
  17.      margin: auto;
  18.   }
  19.    #center {
  20.      margin-bottom: 20px;
  21.   }
  22.    img {
  23.      width: 50px;
  24.   }
  25.    input,select {
  26.      width: 17%;
  27.      padding: 10px;
  28.      margin-right: 30px;
  29.      border: 1px solid #ccc;
  30.      border-radius: 4px;
  31.   }
  32.    .btn {
  33.      background-color: #ccc;
  34.   }
  35.  </style>
  36. </head>
  37. <body>
  38.  <div id="app">
  39.    <div id="center">
  40.      <!-- 通过 v-model 绑定表单项数据,而这些变量,必须在data中定义 -->
  41.     姓名: <input type="text" v-model="name">
  42.     性别:
  43.      <select v-model="gender">
  44.        <option value="1"></option>
  45.        <option value="2"></option>
  46.      </select>
  47.     职位:
  48.      <select v-model="job">
  49.        <option value="1">讲师</option>
  50.        <option value="2">班主任</option>
  51.        <option value="3">其他</option>
  52.      </select>
  53.      
  54.      <input class="btn" type="button" value="查询">
  55.    </div>
  56.    
  57.    <table>
  58.      <tr>
  59.        <th>序号</th>
  60.        <th>姓名</th>
  61.        <th>头像</th>
  62.        <th>性别</th>
  63.        <th>职位</th>
  64.        <th>入职时间</th>
  65.        <th>更新时间</th>
  66.      </tr>
  67.      <tr v-for="(user, index) in userList" :key="user.id">
  68.        <td>{{index + 1}}</td>
  69.        <td>{{user.name}}</td>
  70.        <td> <img :src="user.image"> </td>
  71.        <td>
  72.          <span v-if="user.gender == 1"></span>
  73.          <span v-else-if="user.gender == 2"></span>
  74.          <span v-else>其他</span>
  75.        </td>
  76.        <td>
  77.          <span v-if="user.job == 1">讲师</span>
  78.          <span v-else-if="user.job == 2">班主任</span>
  79.          <span v-else>其他</span>
  80.        </td>
  81.        <td>{{user.entrydate}}</td>
  82.        <td>{{user.updatetime}}</td>
  83.      </tr>
  84.    </table>
  85.   {{name}} - {{gender}} - {{job}}
  86.  </div>
  87.  <script type="module">
  88.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  89.    createApp({
  90.      data() {
  91.        return {
  92.          //定义数据
  93.          name: '',
  94.          gender: '',
  95.          job: '',
  96.          
  97.          userList: [
  98.           {
  99.              "id": 1,
  100.              "name": "谢逊",
  101.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
  102.              "gender": 1,
  103.              "job": 1,
  104.              "entrydate": "2023-06-09",
  105.              "updatetime": "2023-07-01 00:00:00"
  106.           },
  107.           {
  108.              "id": 2,
  109.              "name": "韦一笑",
  110.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
  111.              "gender": 1,
  112.              "job": 1,
  113.              "entrydate": "2023-06-09",
  114.              "updatetime": "2023-07-01 00:00:00"
  115.           },
  116.           {
  117.              "id": 3,
  118.              "name": "黛绮丝",
  119.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/3.jpg",
  120.              "gender": 2,
  121.              "job": 2,
  122.              "entrydate": "2023-06-09",
  123.              "updatetime": "2023-07-01 00:00:00"
  124.           },
  125.           {
  126.              "id": 4,
  127.              "name": "殷天正",
  128.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
  129.              "gender": 1,
  130.              "job": 3,
  131.              "entrydate": "2023-06-09",
  132.              "updatetime": "2023-07-01 00:00:00"
  133.           }
  134.         ]
  135.       }
  136.     },
  137.   }).mount("#app");
  138.  </script>
  139. </body>
  140. </html>

最终在浏览器中执行,我们会看到,我们是可以实时获取到表单的数据的,因为已经将其绑定到了 name、gender、job 数据模型中 。

那现在我们已经可以正常的获取到表单的数据,正常的业务操作应该是点击 "查询" 之后,要执行查询操作。 那接下来,我们就先来为 "查询" 按钮绑定事件,点击查询按钮,获取到表单数据,并输出出来 。

3.7 v-on

3.7.1 介绍

作用:为html标签绑定事件(添加时间监听)

语法:

  • v-on:事件名="内联语句"

    • <input type="button" value="点我一下试试" v-on:click="console.log('试试就试试');">
  • v-on:事件名="函数名"

    • <input type="button" value="点我一下试试" v-on:click="handle">

      这里的handle函数,就需要在Vue应用实例创建的时候创建出来,在methods定义。

  • 简写为 @事件名="…"

3.7.2 演示

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.  <title>v-on入门</title>
  7. </head>
  8. <body>
  9.  
  10.  <div id="app">
  11.    <input type="button" value="点我一下试试" v-on:click="handle">
  12.    <input type="button" value="再点我一下试试" @click="handle">
  13.  </div>
  14.  
  15.  <script type="module">
  16.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  17.    createApp({
  18.      data(){
  19.        return {
  20.          name: 'Vue'
  21.       }
  22.     },
  23.      methods: {
  24.        handle(){
  25.          console.log('试试就试试');
  26.       }
  27.     }
  28.   }).mount('#app')
  29.  </script>
  30. </body>
  31. </html>

3.7.3 案例-事件绑定

那接下来,我们就案例中的 "查询" 按钮绑定事件。 就需要用到上述的 v-on 指令。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.  <title>Vue3-案例1</title>
  8.  <style>
  9.    table,th,td {
  10.      border: 1px solid #000;
  11.      border-collapse: collapse;
  12.      line-height: 50px;
  13.      text-align: center;
  14.   }
  15.    #center,table {
  16.      width: 60%;
  17.      margin: auto;
  18.   }
  19.    #center {
  20.      margin-bottom: 20px;
  21.   }
  22.    img {
  23.      width: 50px;
  24.   }
  25.    input,select {
  26.      width: 17%;
  27.      padding: 10px;
  28.      margin-right: 30px;
  29.      border: 1px solid #ccc;
  30.      border-radius: 4px;
  31.   }
  32.    .btn {
  33.      background-color: #ccc;
  34.   }
  35.  </style>
  36. </head>
  37. <body>
  38.  <div id="app">
  39.    <div id="center">
  40.     姓名: <input type="text" v-model="name">
  41.     性别:
  42.      <select v-model="gender">
  43.        <option value="1"></option>
  44.        <option value="2"></option>
  45.      </select>
  46.     职位:
  47.      <select v-model="job">
  48.        <option value="1">讲师</option>
  49.        <option value="2">班主任</option>
  50.        <option value="3">其他</option>
  51.      </select>
  52.      
  53.      <!-- <input class="btn" type="button" value="查询" v-on:click="handle"> -->
  54.      <input class="btn" type="button" value="查询" @click="handle">
  55.    </div>
  56.    
  57.    <table>
  58.      <tr>
  59.        <th>序号</th>
  60.        <th>姓名</th>
  61.        <th>头像</th>
  62.        <th>性别</th>
  63.        <th>职位</th>
  64.        <th>入职时间</th>
  65.        <th>更新时间</th>
  66.      </tr>
  67.      <tr v-for="(user, index) in userList" :key="user.id">
  68.        <td>{{index + 1}}</td>
  69.        <td>{{user.name}}</td>
  70.        <td> <img :src="user.image"> </td>
  71.        <td>
  72.          <span v-if="user.gender == 1"></span>
  73.          <span v-else-if="user.gender == 2"></span>
  74.          <span v-else>其他</span>
  75.        </td>
  76.        <td>
  77.          <span v-if="user.job == 1">讲师</span>
  78.          <span v-else-if="user.job == 2">班主任</span>
  79.          <span v-else>其他</span>
  80.        </td>
  81.        <td>{{user.entrydate}}</td>
  82.        <td>{{user.updatetime}}</td>
  83.      </tr>
  84.    </table>
  85.  </div>
  86.  <script type="module">
  87.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  88.    createApp({
  89.      data() {
  90.        return {
  91.          name: '',
  92.          gender: '',
  93.          job: '',
  94.          userList: [
  95.           {
  96.              "id": 1,
  97.              "name": "谢逊",
  98.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
  99.              "gender": 1,
  100.              "job": "班主任",
  101.              "entrydate": "2023-06-09",
  102.              "updatetime": "2023-07-01 00:00:00"
  103.           },
  104.           {
  105.              "id": 2,
  106.              "name": "韦一笑",
  107.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
  108.              "gender": 1,
  109.              "job": "班主任",
  110.              "entrydate": "2023-06-09",
  111.              "updatetime": "2023-07-01 00:00:00"
  112.           },
  113.           {
  114.              "id": 3,
  115.              "name": "黛绮丝",
  116.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/3.jpg",
  117.              "gender": 2,
  118.              "job": "班主任",
  119.              "entrydate": "2023-06-09",
  120.              "updatetime": "2023-07-01 00:00:00"
  121.           },
  122.           {
  123.              "id": 4,
  124.              "name": "殷天正",
  125.              "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
  126.              "gender": 1,
  127.              "job": "班主任",
  128.              "entrydate": "2023-06-09",
  129.              "updatetime": "2023-07-01 00:00:00"
  130.           }
  131.         ]
  132.       }
  133.     },
  134.      methods: {
  135.       handle: function(){
  136.         console.log(`查询啦, 查询条件: name=${this.name}, gender=${this.gender}, job=${this.job}`);
  137.       }
  138.     }
  139.   }).mount("#app");
  140.  </script>
  141. </body>
  142. </html>

浏览器打开此页面,测试,我们会看控制台输出了我们所选择的查询条件。

注意:在methods声明的方法中,如果想要获取Vue的数据,可以通过this关键字,获取到vue应用实例,从而获取到实例中的数据信息

扩展:虚拟DOM

虚拟DOM

DOM操作是Web开发中比较消耗资源并且低效的操作,尤其在用户界面频繁更新的情况,更是严重.在每次数据更新时重新渲染整个DOM树会导致应用程序性能下降.

为了解决这种问题.虚拟DOM被引入到前端开发中.虚拟DOM把整个DOM树抽象成一个JS对象,开发这直接操作这个JS对象,最后在把JS对象映射到DOM上.

在Vue中,每个组件树都有一个响应的虚拟DOM树.当应用状态发生变化时,Vue会比较新状态和旧状态的虚拟DOM树,找出发生变化的部分并渲染成具体DOM操作.最终需要对变化的部分进行DOM操作.

虚拟DOM中key的作用:(面试题)

key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:

对比规则:

(1).旧虚拟DOM中找到了与新虚拟DOM相同的key:

  • ①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!

  • ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。

(2).旧虚拟DOM中未找到与新虚拟DOM相同的key 创建新的真实DOM,随后渲染到到页面。

用index作为key可能会引发的问题

  1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。

  2. 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。

开发中如何选择key?

1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。

2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

4. Ajax

4.1 概述

我们前端页面中的数据,如下图所示的表格中的学生信息,应该来自于后台,那么我们的后台和前端是互不影响的2个程序,那么我们前端应该如何从后台获取数据呢?因为是2个程序,所以必须涉及到2个程序的交互,所以这就需要用到我们接下来学习的Ajax技术。

Ajax: 全称Asynchronous JavaScript And XML,异步的JavaScript和XML。其作用有如下2点:

  • 与服务器进行数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。

  • 异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用的校验等等。

我们详细的解释一下Ajax技术的2个作用

  • 与服务器进行数据交互

    如下图所示前端资源被浏览器解析,但是前端页面上缺少数据,前端可以通过Ajax技术,向后台服务器发起请求,后台服务器接受到前端的请求,从数据库中获取前端需要的资源,然后响应给前端,前端在通过我们学习的vue技术,可以将数据展示到页面上,这样用户就能看到完整的页面了。此处可以对比JavaSE中的网络编程技术来理解。

  • 异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术。

    如下图所示,当我们再百度搜索java时,下面的联想数据是通过Ajax请求从后台服务器得到的,在整个过程中,我们的Ajax请求不会导致整个百度页面的重新加载,并且只针对搜索栏这局部模块的数据进行了数据的更新,不会对整个页面的其他地方进行数据的更新,这样就大大提升了页面的加载速度,用户体验高。

4.2 同步异步

针对于上述Ajax的局部刷新功能是因为Ajax请求是异步的,与之对应的有同步请求。接下来我们介绍一下异步请求和同步请求的区别。

  • 同步请求发送过程如下图所示:

浏览器页面在发送请求给服务器,在服务器处理请求的过程中,浏览器页面不能做其他的操作。只能等到服务器响应结束后才能,浏览器页面才能继续做其他的操 作。

  • 异步请求发送过程如下图所示:

浏览器页面发送请求给服务器,在服务器处理请求的过程中,浏览器页面还可以做其他的操作。

4.3 原生Ajax

对于Ajax技术有了充分的认知了,我们接下来通过代码来演示Ajax的效果。此处我们先采用原生的Ajax代码来演示。因为Ajax请求是基于客户端发送请求,服务器响应数据的技术。所以为了完成快速入门案例,我们需要提供服服务器端和编写客户端。

1). 服务器端

因为我们暂时还没学过服务器端的代码,所以此处已经直接提供好了服务器端的请求地址,我们前端直接通过Ajax请求访问该地址即可。后台服务器地址https://mock.apifox.cn/m1/3083103-0-default/emps/list

上述地址我们也可以直接通过浏览器来访问,访问结果如图所示:只截取部分数据

2). 客户端

客户端的Ajax请求代码如下有如下4步,接下来我们跟着步骤一起操作一下。

  1. 创建XMLHttpRequest对象:用于和服务器交换数据

  2. 向服务器发送请求

  3. 获取服务器响应数据

具体代码如下(在资料中已经提供,无需自己编写):

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.    <meta charset="UTF-8">
  5.    <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.    <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.    <title>原生Ajax</title>
  8. </head>
  9. <body>  
  10.    <input id="btn1" type="button" value="获取数据">
  11.    
  12.    <div id="div1"></div>
  13.    <script>
  14.        document.querySelector('#btn1').addEventListener('click', ()=> {
  15.          //1. 创建XMLHttpRequest
  16.          var xmlHttpRequest  = new XMLHttpRequest();
  17.          
  18.          //2. 发送异步请求
  19.          xmlHttpRequest.open('GET', 'https://mock.apifox.cn/m1/3083103-0-default/emps/list');
  20.          xmlHttpRequest.send();//发送请求
  21.          
  22.          //3. 获取服务响应数据
  23.          xmlHttpRequest.onreadystatechange = function(){
  24.              if(xmlHttpRequest.readyState == 4 && xmlHttpRequest.status == 200){
  25.                  document.getElementById('div1').innerHTML = xmlHttpRequest.responseText;
  26.             }
  27.         }
  28.       })
  29.    </script>
  30. </body>
  31. </html>

最后我们通过浏览器打开页面,请求点击按钮,发送Ajax请求,最终显示结果如下图所示:

4.4 Axios

上述原生的Ajax请求的代码编写起来还是比较繁琐的,所以接下来我们学习一门更加简单的发送Ajax请求的技术Axios 。Axios是对原生的AJAX进行封装,简化书写。Axios官网是:https://www.axios-http.cn

4.4.1 Axios的基本使用

Axios的使用比较简单,主要分为2步:

  • 引入Axios文件

    <script src="js/axios-0.18.0.js"></script>

  • 使用Axios发送请求,并获取响应结果,官方提供的api很多,此处给出2种,如下

    • 发送 get 请求

      axios({
          method:"get",
          url:"https://mock.apifox.cn/m1/3083103-0-default/emps/list"
      }).then(function (resp){
          alert(resp.data);
      })
    • 发送 post 请求

      axios({
          method:"post",
          url:"https://mock.apifox.cn/m1/3083103-0-default/emps/update",
          data:"id=1"
      }).then(function (resp){
          alert(resp.data);
      });

    axios()是用来发送异步请求的,小括号中使用 js的JSON对象传递请求相关的参数:

    • method属性:用来设置请求方式的。取值为 get 或者 post。

    • url属性:用来书写请求的资源路径。如果是 get 请求,需要将请求参数拼接到路径的后面,格式为: url?参数名=参数值&参数名2=参数值2。

    • data属性:作为请求体被发送的数据。也就是说如果是 post 请求的话,数据需要作为 data 属性的值。

    then() 需要传递一个匿名函数。我们将 then()中传递的匿名函数称为 回调函数,意思是该匿名函数在发送请求时不会被调用,而是在成功响应后调用的函数。而该回调函数中的 resp 参数是对响应的数据进行封装的对象,通过 resp.data 可以获取到响应的数据。

4.4.2 Axios入门程序

  • 后端实现

    查询所有员工信息服务器地址(GET):https://mock.apifox.cn/m1/3083103-0-default/emps/list

    更新员工信息服务器地址(POST):https://mock.apifox.cn/m1/3083103-0-default/emps/update

  • 前端实现

    A. 引入axios.min.js 【联网加载 或 引入下载好的本地的JS都可以】

    B. 为两个 "按钮" 绑定事件

    C. 触发事件之后,基于axios发送异步请求,分别发送GET请求、POST请求获取数据

    完整代码如下:

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. <head>
    4.    <meta charset="UTF-8">
    5.    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6.    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7.    <title>Ajax-Axios</title>
    8. </head>
    9. <body>
    10.    
    11.    <input type="button" value="获取数据GET" id="btnGet">
    12.    <input type="button" value="删除数据POST" id="btnPost">
    13.    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    14.    <script>
    15.        //GET请求
    16.        document.querySelector('#btnGet').addEventListener('click', ()=>{
    17.            axios({
    18.                url: 'https://mock.apifox.cn/m1/3083103-0-default/emps/list',
    19.                method: 'GET'
    20.           }).then(result => {
    21.                console.log(result.data);
    22.           }).catch(err => {
    23.                console.log(err);
    24.           })
    25.       })
    26.        //POST请求
    27.        document.querySelector('#btnPost').addEventListener('click', ()=>{
    28.            axios({
    29.                url: 'https://mock.apifox.cn/m1/3083103-0-default/emps/update',
    30.                method: 'POST',
    31.                data:'id=1'
    32.           }).then(result => {
    33.                console.log(result.data);
    34.           }).catch(err => {
    35.                console.log(err);
    36.           })
    37.       })
    38.    </script>
    39. </body>
    40. </html>

    浏览器打开,f12抓包,然后分别点击2个按钮,查看控制台效果如下:

4.4.3 请求方法的别名

Axios还针对不同的请求,提供了别名方式的api,具体格式如下:

axios.请求方式(url [, data [, config]])

具体如下:

方法描述
axios.get(url [, config])发送get请求
axios.delete(url [, config])发送delete请求
axios.post(url [, data[, config]])发送post请求
axios.put(url [, data[, config]])发送put请求

我们目前只关注get和post请求,所以在上述的入门案例中,我们可以将get请求代码改写成如下:

axios.get("https://mock.apifox.cn/m1/3083103-0-default/emps/list").then(result => {
    console.log(result.data);
})

post请求改写成如下:

axios.post("https://mock.apifox.cn/m1/3083103-0-default/emps/update","id=1").then(result => {
    console.log(result.data);
})

4.5 案例-Ajax异步获取数据

通过上面的学习,我们已经清楚了什么是Ajax,已经如何发送Ajax异步请求。 那解下来呢,我们就要完成员工列表数据加载的这个案例。

需求:当点击查询按钮时,发送Ajax异步请求,根据传递的查询条件,动态获取数据,渲染列表页面。

服务端地址:https://web-server.itheima.net/emps/list

具体代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.  <title>Vue3-案例1</title>
  8.  <style>
  9.    table,th,td {
  10.      border: 1px solid #000;
  11.      border-collapse: collapse;
  12.      line-height: 50px;
  13.      text-align: center;
  14.   }
  15.    #center,table {
  16.      width: 60%;
  17.      margin: auto;
  18.   }
  19.    #center {
  20.      margin-bottom: 20px;
  21.   }
  22.    img {
  23.      width: 50px;
  24.   }
  25.    input,select {
  26.      width: 17%;
  27.      padding: 10px;
  28.      margin-right: 30px;
  29.      border: 1px solid #ccc;
  30.      border-radius: 4px;
  31.   }
  32.    .btn {
  33.      background-color: #ccc;
  34.   }
  35.  </style>
  36. </head>
  37. <body>
  38.  <div id="app">
  39.    <div id="center">
  40.     姓名: <input type="text" v-model="name">
  41.     性别:
  42.      <select v-model="gender">
  43.        <option value="1"></option>
  44.        <option value="2"></option>
  45.      </select>
  46.     职位:
  47.      <select v-model="job">
  48.        <option value="1">讲师</option>
  49.        <option value="2">班主任</option>
  50.        <option value="3">其他</option>
  51.      </select>
  52.      
  53.      <!-- <input class="btn" type="button" value="查询" v-on:click="handle"> -->
  54.      <input class="btn" type="button" value="查询" @click="handle">
  55.    </div>
  56.    
  57.    <table>
  58.      <tr>
  59.        <th>序号</th>
  60.        <th>姓名</th>
  61.        <th>头像</th>
  62.        <th>性别</th>
  63.        <th>职位</th>
  64.        <th>入职时间</th>
  65.        <th>更新时间</th>
  66.      </tr>
  67.      <tr v-for="(user, index) in userList" :key="user.id">
  68.        <td>{{index + 1}}</td>
  69.        <td>{{user.name}}</td>
  70.        <td> <img :src="user.image"> </td>
  71.        <td>
  72.          <span v-if="user.gender == 1"></span>
  73.          <span v-else-if="user.gender == 2"></span>
  74.          <span v-else>其他</span>
  75.        </td>
  76.        <td>
  77.          <span v-if="user.job == 1">讲师</span>
  78.          <span v-else-if="user.job == 2">班主任</span>
  79.          <span v-else>其他</span>
  80.        </td>
  81.        <td>{{user.entrydate}}</td>
  82.        <td>{{user.updatetime}}</td>
  83.      </tr>
  84.    </table>
  85.  </div>
  86.  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  87.  <script type="module">
  88.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  89.    createApp({
  90.      data() {
  91.        return {
  92.          name: '',
  93.          gender: '',
  94.          job: '',
  95.          userList: []
  96.       }
  97.     },
  98.      methods: {
  99.       handle: function(){
  100.         console.log(`查询啦, 查询条件: name=${this.name}, gender=${this.gender}, job=${this.job}`);
  101.         axios.get(`https://web-server.itheima.net/emps/list?name=${this.name}&gender=${this.gender}&job=${this.job}`).then((result) => {
  102.            this.userList = result.data.data;
  103.         })
  104.       }
  105.     }
  106.   }).mount("#app");
  107.  </script>
  108. </body>
  109. </html>

打开浏览器测试:

经过上面的测试之后,我们看到,当我们点击 "查询" 按钮时,确实可以发送Ajax异步请求,动态获取数据。但是,我们打开这个页面时,表格内容却是一片空白,只有点击了查询按钮才会展示出数据。 而在正常的系统中,应该是进入页面时,就会展示出表格中的数据的。

那如何在页面打开之后,就自动执行查询呢? 那此时,我们就需要用到Vue中生命周期的相关函数了。那接下来,我们就来学习Vue的声明周期。

5. 生命周期

5.1 介绍

vue的生命周期:指的是vue对象从创建到销毁的过程。

vue的生命周期包含8个阶段:每触发一个生命周期事件,会自动执行一个生命周期方法,这些生命周期方法也被称为钩子方法。其完整的生命周期如下图所示:

状态阶段周期
beforeCreate创建前
created创建后
beforeMount挂载前
mounted挂载完成
beforeUpdate更新前
updated更新后
beforeDestroy销毁前
destroyed销毁后

下图是 Vue 官网提供的从创建 Vue 到效果 Vue 对象的整个过程及各个阶段对应的钩子函数:

其中我们需要重点关注的是mounted,其他的我们了解即可。

mounted:挂载完成,Vue初始化成功,HTML页面渲染成功。以后我们一般用于页面初始化自动的ajax请求后台数据

5.2 案例-员工列表查询

那我们要想在页面加载完毕,就查询出员工列表,就可以在mounted钩子函数中,发送异步请求查询员工数据了。

具体代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.  <meta charset="UTF-8">
  5.  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6.  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7.  <title>Vue3-案例1</title>
  8.  <style>
  9.    table,th,td {
  10.      border: 1px solid #000;
  11.      border-collapse: collapse;
  12.      line-height: 50px;
  13.      text-align: center;
  14.   }
  15.    #center,table {
  16.      width: 60%;
  17.      margin: auto;
  18.   }
  19.    #center {
  20.      margin-bottom: 20px;
  21.   }
  22.    img {
  23.      width: 50px;
  24.   }
  25.    input,select {
  26.      width: 17%;
  27.      padding: 10px;
  28.      margin-right: 30px;
  29.      border: 1px solid #ccc;
  30.      border-radius: 4px;
  31.   }
  32.    .btn {
  33.      background-color: #ccc;
  34.   }
  35.  </style>
  36. </head>
  37. <body>
  38.  <div id="app">
  39.    <div id="center">
  40.     姓名: <input type="text" v-model="name">
  41.     性别:
  42.      <select v-model="gender">
  43.        <option value="1"></option>
  44.        <option value="2"></option>
  45.      </select>
  46.     职位:
  47.      <select v-model="job">
  48.        <option value="1">讲师</option>
  49.        <option value="2">班主任</option>
  50.        <option value="3">其他</option>
  51.      </select>
  52.      
  53.      <!-- <input class="btn" type="button" value="查询" v-on:click="handle"> -->
  54.      <input class="btn" type="button" value="查询" @click="handle">
  55.    </div>
  56.    
  57.    <table>
  58.      <tr>
  59.        <th>序号</th>
  60.        <th>姓名</th>
  61.        <th>头像</th>
  62.        <th>性别</th>
  63.        <th>职位</th>
  64.        <th>入职时间</th>
  65.        <th>更新时间</th>
  66.      </tr>
  67.      <tr v-for="(user, index) in userList" :key="user.id">
  68.        <td>{{index + 1}}</td>
  69.        <td>{{user.name}}</td>
  70.        <td> <img :src="user.image"> </td>
  71.        <td>
  72.          <span v-if="user.gender == 1"></span>
  73.          <span v-else-if="user.gender == 2"></span>
  74.          <span v-else>其他</span>
  75.        </td>
  76.        <td>
  77.          <span v-if="user.job == 1">讲师</span>
  78.          <span v-else-if="user.job == 2">班主任</span>
  79.          <span v-else>其他</span>
  80.        </td>
  81.        <td>{{user.entrydate}}</td>
  82.        <td>{{user.updatetime}}</td>
  83.      </tr>
  84.    </table>
  85.  </div>
  86.  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  87.  <script type="module">
  88.    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  89.    createApp({
  90.      data() {
  91.        return {
  92.          name: '',
  93.          gender: '',
  94.          job: '',
  95.          userList: []
  96.       }
  97.     },
  98.      methods: {
  99.       handle: function(){
  100.         console.log(`查询啦, 查询条件: name=${this.name}, gender=${this.gender}, job=${this.job}`);
  101.         axios.get(`https://web-server.itheima.net/emps/list?name=${this.name}&gender=${this.gender}&job=${this.job}`).then((result) => {
  102.            this.userList = result.data.data;
  103.         })
  104.       }
  105.     },
  106.      mounted() {
  107.        this.handle();
  108.     },
  109.   }).mount("#app");
  110.  </script>
  111. </body>
  112. </html>

打开浏览器,进行测试,我们看到,当我们访问这个页面之后,会自动查询所有的员工数据 。

5.3 案例-省市区

5.3.1 需求

  • 需求:页面加载完毕后,默认加载并展示出第一个省、第一个市、第一个区。

  • 如图所示:

5.3.2 分析

  1. 要想在页面加载完成后,默认加载出第一个省、第一个省对应的第一个市、第一个市对应的第一个区。 就应该用到vue的钩子函数 mounted。

  2. 那要想加载出省市区,就需要发送3次异步请求,第一次获取省。

  3. 那什么时候发送第二次异步请求,获取市呢 ? 应该是在第一次异步请求完成之后,我们获取到第一个省份,然后再根据省份的ID查询市。

  4. 那什么时候发送第三次异步请求,获取区呢 ?应该是在第二次异步请求完成之后,我们获取到第一个市,然后再根据市的ID查询区。从获取到区 。

思考:如何在第一次异步请求成功后,再发送第二次异步请求获取数据呢 ?

那么此时,我们就可以在第一个请求的成功回调函数中,来发送第二次请求 。这样就可以保证,是第一个请求成功,才发送的第二次请求。

5.3.3 实现

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  <head>
  4.    <meta charset="UTF-8" />
  5.    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6.    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.    <title>Vue3-案例1</title>
  8.    <style>
  9.      #center {
  10.        margin-bottom: 20px;
  11.     }
  12.      input,
  13.      select {
  14.        width: 17%;
  15.        padding: 10px;
  16.        margin-right: 30px;
  17.        border: 1px solid #ccc;
  18.        border-radius: 4px;
  19.     }
  20.    </style>
  21.  </head>
  22.  <body>
  23.    <div id="app">
  24.      <div id="center">
  25.       省:
  26.        <select v-model="province">
  27.          <option v-for="p in provinces" :key="p.id" :value="p.id">{{p.name}}</option>
  28.        </select>
  29.       市:
  30.        <select v-model="city">
  31.          <option v-for="c in cities" :key="c.id" :value="c.id">{{c.name}}</option>
  32.        </select>
  33.       区:
  34.        <select v-model="area">
  35.          <option v-for="a in areas" :key="a.id" :value="a.id">{{a.name}}</option>
  36.        </select>
  37.      </div>
  38.    </div>
  39.    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  40.    <script type="module">
  41.      import { createApp } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
  42.      createApp({
  43.        data() {
  44.          return {
  45.            province: '',
  46.            city: '',
  47.            area: '',
  48.            provinces: [],
  49.            cities: [],
  50.            areas: [],
  51.         };
  52.       },
  53.        methods: {
  54.          search() {
  55.            axios.get(`https://web-server.itheima.net/province`).then((result) => {
  56.                this.provinces = result.data.data;
  57.                this.province = this.provinces[0].id;
  58.                axios.get(`https://web-server.itheima.net/city?pid=${this.province}`).then((result) => {
  59.                    this.cities = result.data.data;
  60.                    this.city = this.cities[0].id;
  61.                    axios.get(`https://web-server.itheima.net/area?cid=xxx${this.city}`).then((result) => {
  62.                        this.areas = result.data.data;
  63.                        this.area = this.areas[0].id;
  64.                     });
  65.                 });
  66.             });
  67.         }
  68.       },
  69.        mounted() {
  70.          this.search();
  71.       },
  72.     }).mount("#app");
  73.    </script>
  74.  </body>
  75. </html>

打开浏览器测试:

经过测试我们看到,通过这种方案,确实可以实现该功能。在页面加载完毕后,确实默认将第一个省、第一个省对应的第一个市、第一个市对应的第一个区展示出来。但是呢,上面我们编写的代码呢,类似于 "套娃",一层套一层,可读性、可维护性都是比较差的 。 这种问题呢,也被称为 "回调地狱"。

那如果出现这样的驱动,我们如何来优化我们的代码,以增强程序的可读性和可维护性呢?

那这里呢,我们是可以借助于JS中给我们提供的async/await来解决这个问题的。

5.3.4 async/await

可以通过async、await来解决回调函数地狱问题。async就是来声明一个异步方法,await是用来等待异步任务执行。

await关键字只在async函数内有效,await关键字取代了原来的then成功回调函数,且await会等待获取到请求成功的结果值。

接下来,我们就来通过async/await 来解决刚才遇到的 "回调函数地狱" 问题。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  <head>
  4.    <meta charset="UTF-8" />
  5.    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6.    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.    <title>Vue3-案例1</title>
  8.    <style>
  9.      #center {
  10.        margin-bottom: 20px;
  11.     }
  12.      input,
  13.      select {
  14.        width: 17%;
  15.        padding: 10px;
  16.        margin-right: 30px;
  17.        border: 1px solid #ccc;
  18.        border-radius: 4px;
  19.     }
  20.    </style>
  21.  </head>
  22.  <body>
  23.    <div id="app">
  24.      <div id="center">
  25.       省:
  26.        <select v-model="province">
  27.          <option v-for="p in provinces" :key="p.id" :value="p.id">{{p.name}}</option>
  28.        </select>
  29.       市:
  30.        <select v-model="city">
  31.          <option v-for="c in cities" :key="c.id" :value="c.id">{{c.name}}</option>
  32.        </select>
  33.       区:
  34.        <select v-model="area">
  35.          <option v-for="a in areas" :key="a.id" :value="a.id">{{a.name}}</option>
  36.        </select>
  37.      </div>
  38.    </div>
  39.    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  40.    <script type="module">
  41.      import { createApp } from "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
  42.      createApp({
  43.        data() {
  44.          return {
  45.            province: '',
  46.            city: '',
  47.            area: '',
  48.            
  49.            provinces: [],
  50.            cities: [],
  51.            areas: [],
  52.         };
  53.       },
  54.        methods: {
  55.          async search() {
  56.            const presult = await axios.get(`https://web-server.itheima.net/province`);
  57.            this.provinces = presult.data.data;
  58.            this.province = this.provinces[0].id;
  59.            
  60.            const cresult = await axios.get(`https://web-server.itheima.net/city?pid=${this.province}`);
  61.            this.cities = cresult.data.data;
  62.            this.city = this.cities[0].id;
  63.            const aresult = await axios.get(`https://web-server.itheima.net/area?cid=${this.city}`);
  64.            this.areas = aresult.data.data;
  65.            this.area = this.areas[0].id;
  66.         }
  67.       },
  68.        mounted() {
  69.          this.search();
  70.       },
  71.     }).mount("#app");
  72.    </script>
  73.  </body>
  74. </html>

打开浏览器测试,发现实现的效果是一样的:

我们会看到,通过async、await修饰的函数,简化了原来 then 成功回调函数的编写,使我们的代码可读性更强了,也更加便于项目的维护。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/821686
推荐阅读
相关标签
  

闽ICP备14008679号