Skip to content

✌️ ​Vue


一、概述


  • Vue( 读音 /vjuː /, 类似于 view ),

    是一款用于 构建用户界面渐进式JavaScript 框架


  • 官方网站 : https://cn.vuejs.org/


  • 1) . 构建用户界面

    • 构建用户界面是指,在 Vue 中,可以 基于数据渲染 出用户看到的界面。

      比如将来服务器端返回给前端的原始数据(JSON),就是如下这个样子:

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

    • 而上面的这些原始数据,用户是看不懂的。 而我们开发人员呢,可以使用 Vue 中提供的操作,

      将原始数据遍历、解析出来,从而渲染呈现出用户所能看懂的界面,如下所示:

    4475b6d5-7c7c-46d5-bcaa-07b34ae3ba67
  • 2) . 渐进式

    • 渐进式中的渐进呢,字面意思就是 "循序渐进" 。Vue生态中的语法呢是非常多的,

      比如声明式渲染、组件系统、客户端路由(VueRouter)、

      状态管理(Vuex、Pinia)、构建工具(Webpack、Vite)等等。

    dcc964d4-1030-450e-b067-d17b5a500272
    • 所谓渐进,指的是我们使用 Vue 框架呢,

      我们不需要把所有的组件、语法全部学习完毕才可以使用 Vue

      而是,我们学习一点就可以使用一点了,比如:

      • 我们学习了声明式渲染,我们就可以使用 Vue 来构建用户界面了。
      • 我们再学习了组件系统,我们就可以使用 Vue 中的组件,从而来复用了。
      • 我们再学习了路由 VueRouter,就可以使用 Vue 中的中的路由功能了。

    也就是说,并不需要全部学习完毕就可以直接使用 Vue 进行开发,

    简化操作、提高效率了。 Vue 是一个框架,但其实也是一个生态。


二、快速上手


2.1 需求

  • 在入门程序中,最终我们需要将准备的数据 message 的值,

    基于 Vue 渲染展示在页面中,最终呈现的形式如下:

f16a374a-b73d-478d-a1d8-1d38d9552ddf

2.2 步骤


  • 1) . 准备工作

    • 准备一个 html 文件,并在其中引入 Vue 模块 (参考官方文档,复制过来即可)

      【注意:模块化的 js ,引入时,需要设置 type="module"

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

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

html
<body>
    
    <!-- 3.准备元素 (div),被 Vue 控制 -->
    <div id="app">
        
    </div>
    


    <!-- 模块化 js 要声明 module -->
    <script type="module">

        // 1. 引入 Vue 模块
        import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
        
        // 2. 创建 Vue 程序的应用实例,控制视图的元素
        createApp({

            
            
        }).mount("#app") // mount 去需要控制的元素
    </script>
    
</body>

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

  • 2) . 数据驱动视图

    • 准备数据。 在创建 Vue 应用实例的时候,传入了一个 js 对象,在这个 js 对象中,

      我们要定义一个 data 方法,这个 data 方法的返回值就是 Vue 中的数据。

    • 通过插值表达式渲染页面。 插值表达式的写法:(两个 大括号 / 花括号 包裹)

f70be6ba-b2bf-4eaa-a1eb-1ddd813aa1f7
  • 3) . 实现
html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue-快速入门</title>
</head>
<body>
    <!-- 3.准备元素 (div),被 Vue 控制 -->
    <div id="app">
        <h1>{{message}}</h1>
    </div>
    


    <!-- 模块化 js 要声明 module -->
    <script type="module">

        // 1. 引入 Vue 模块
        import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';
        
        // 2. 创建 Vue 程序的应用实例,控制视图的元素
        createApp({

            data(){
                return {
                    message : "Hello Vue"
                }
            }
            
        }).mount("#app") // mount 去需要控制的元素


    </script>
</body>
</html>

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

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

  • 插值表达式中编写的变量,一定是 Vue 中定义的数据,

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

  • Vue 应用实例接管的区域是 '#app' ,超出这个范围,就不受 Vue 控制了


三、Vue 指令


3.1 概述


指令:指的是 HTML 标签上带有 v- 前缀的特殊属性,

不同指令具有不同含义,可以实现不同的功能 。例如:v-ifv-for


  • 形式:
html
<p v-xxx="....">.....</p>

  • 常见指令:
指令作用
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


  • 作用:列表渲染,遍历容器的元素或者对象的属性
  • 语法:
html
<tr v-for="(item,index) in items" :key="item.id">{{item}}</tr>
  • 参数说明:
    • items 为遍历的数组

    • item 为遍历出来的元素

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

    • key :

      • 作用:给元素添加的唯一标识,便于 vue 进行列表项的正确排序复用,提升渲染性能
      • 推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key (会变化,不对应)

  • 注意:遍历的数组,必须在 data 中定义;

    要想让哪个标签循环展示多次,就在哪个标签上使用 v-for 指令。


  • 案例代码:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tlias智能学习辅助系统</title>
    <style>
      body {
        margin: 0;
      }

      /* 顶栏样式 */
      .header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        background-color: #c2c0c0;
        padding: 20px 20px;
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
      }
      
      /* 加大加粗标题 */
      .header h1 {
        margin: 0;
        font-size: 24px;
        font-weight: bold;
      }

      /* 文本链接样式 */
      .header a {
        text-decoration: none;
        color: #333;
        font-size: 16px;
      }

      /* 搜索表单区域 */
      .search-form {
        display: flex;
        align-items: center;
        padding: 20px;
        background-color: #f9f9f9;
      }

      /* 表单控件样式 */
      .search-form input[type="text"], .search-form select {
        margin-right: 10px;
        padding: 10px 10px;
        border: 1px solid #ccc;
        border-radius: 4px;
        width: 26%;
      }

      /* 按钮样式 */
      .search-form button {
        padding: 10px 15px;
        margin-left: 10px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
      }

      /* 清空按钮样式 */
      .search-form button.clear {
        background-color: #6c757d;
      }

      .table {
         min-width: 100%; 
         border-collapse: collapse;
      }

      /* 设置表格单元格边框 */
      .table td, .table th { 
        border: 1px solid #ddd; 
        padding: 8px; 
        text-align: center;
      }
      
      .avatar { 
        width: 30px; 
        height: 30px; 
        object-fit: cover; 
        border-radius: 50%; 
      }

      /* 页脚版权区域 */
    .footer {
        background-color: #c2c0c0;
        color: white;
        text-align: center;
        padding: 10px 0;
        margin-top: 30px;
    }

    .footer .company-name {
        font-size: 1.1em;
        font-weight: bold;
    }

    .footer .copyright {
        font-size: 0.9em;
    }

    #container {
      width: 80%;
      margin: 0 auto;
    }
    </style>
</head>
<body>
    
  <div id="container">
    <!-- 顶栏 -->
    <div class="header">
      <h1>Tlias智能学习辅助系统</h1>
      <a href="#">退出登录</a>
    </div>

    <!-- 搜索表单区域 -->
    <form class="search-form" action="#" method="post">
      <input type="text" name="name" placeholder="姓名" />
      <select name="gender">
          <option value="">性别</option>
          <option value="1">男</option>
          <option value="2">女</option>
      </select>
      <select name="job">
          <option value="">职位</option>
          <option value="1">班主任</option>
          <option value="2">讲师</option>
          <option value="3">学工主管</option>
          <option value="4">教研主管</option>
          <option value="5">咨询师</option>
      </select>
      <button type="submit">查询</button>
      <button type="reset" class="clear">清空</button>
    </form>

    <table class="table table-striped table-bordered">
      <thead>
          <tr>
            <th>序号</th>
            <th>姓名</th>
            <th>性别</th>
            <th>头像</th>
            <th>职位</th>
            <th>入职日期</th>
            <th>最后操作时间</th>
            <th>操作</th>
          </tr>
      </thead>
      <tbody>
          <!-- 需填充位置 --> 
      </tbody>
    </table>

    <!-- 页脚版权区域 -->
    <footer class="footer">
      <p class="company-name">江苏传智播客教育科技股份有限公司</p>
      <p class="copyright">版权所有 Copyright 2006-2024 All Rights Reserved</p>
    </footer>

    <script type="module">
      import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
      createApp({
        data() {
          return {
            empList: [
              { "id": 1,
                "name": "谢逊",
                "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
                "gender": 1,
                "job": "1",
                "entrydate": "2023-06-09",
                "updatetime": "2024-07-30T14:59:38"
              },
              {
                "id": 2,
                "name": "韦一笑",
                "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
                "gender": 1,
                "job": "1",
                "entrydate": "2020-05-09",
                "updatetime": "2023-07-01T00:00:00"
              },
              {
                "id": 3,
                "name": "黛绮丝",
                "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
                "gender": 2,
                "job": "2",
                "entrydate": "2021-06-01",
                "updatetime": "2023-07-01T00:00:00"
              }
            ]
          }
        }
      }).mount('#container')
    </script>

  </div>

</body>
</html>

  • 需求说明:在上面的 <tbody> 位置使用 v-for 填充代码 ,

    相关的数据在 vue 的 data() 部分声明好了,需要使用 v-for + 插值表达式 ... 渲染出来数据


  • 示例代码:
html
<tbody>

    <tr v-for="(e, index) in empList" :key="e.id">
        <td>{{index + 1}}</td>
        <td>{{e.name}}</td>
        <td>{{e.gender == 1 ? "男":"女"}}</td>

        <!-- 1. 插值表达式是不能出现在标签内部的 (下面的写法是错误的) -->
        <td><img class="avatar" src="{{e.image}}" alt="{{e.image}}"></td>

        <!-- 2. job 还没有对应起来 -->
        <td>{{e.job}}</td>

        <td>{{e.entrydate}}</td>
        <td>{{e.updatetime}}</td>
        <td class="btn-group">
            <button class="edit">编辑</button>
            <button class="delete">删除</button>
        </td>
    </tr>
        
</tbody>

  • 暂时表现的效果如下:
微信截图_20250709232217

这些问题将在后面得到解决 ...


3.3 v-bind


  • 作用:动态为 HTML 标签绑定属性值,如设置 hrefsrcstyle 样式等。
  • 语法:
html
<!-- v-bind:属性名="属性值" -->

<img v-bind:src="item.image" width="30px">
  • (语法)简化:可以直接冒号,不用写 v-bind
html
<!-- :属性名="属性值" -->

<img :src="item.image" width="30px">
  • 注意:v-bind 所绑定的数据,必须在 data 中定义或基于 data 中定义的数据而来。

解决之前图像显示的问题:插值表达式是不能出现在标签内部的 !!

  • 示例代码:
html
<tbody>
            
    <tr v-for="(e, index) in empList" :key="e.id">
        <td>{{index + 1}}</td>
        <td>{{e.name}}</td>
        <td>{{e.gender == 1 ? "男":"女"}}</td>

        <td><img class="avatar" v-bind:src="e.image" :alt="e.image"></td>

        <!-- job 还没有对应起来 -->
        <td>{{e.job}}</td>

        <td>{{e.entrydate}}</td>
        <td>{{e.updatetime}}</td>
        <td class="btn-group">
            <button class="edit">编辑</button>
            <button class="delete">删除</button>
        </td>
    </tr>
        
</tbody>
  • 效果:
微信截图_20250709232804

3.4 v-if & v-show


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

  • v-if
    • 语法:v-if="表达式" ,表达式值为 true,显示;false,隐藏
    • 原理:基于条件判断,来控制创建或移除元素节点(条件渲染)
    • 场景:要么显示,要么不显示,不频繁切换的场景
    • 其它:可以配合 v-else-if / v-else 进行链式调用条件判断
    • 注意:v-else-if 必须出现在 v-if 之后,可以出现多个; v-else 必须出现在 v-if/v-else-if 之后 。

  • v-show
    • 语法:v-show="表达式",表达式值为 true,显示;false,隐藏
    • 原理:基于 CSS 样式 display 来控制显示与隐藏
    • 场景:频繁切换显示隐藏的场景

解决上面职位的问题

  • 示例代码:
html
<td>
    <!-- 使用 v-if: 基于条件判断,来控制创建或移除元素节点(条件渲染) -->
    <span v-if="e.job == 1">班主任</span>
    <span v-else-if="e.job == 2">讲师</span>
    <span v-else-if="e.job == 3">学工主管</span>
    <span v-else-if="e.job == 4">教研主管</span>
    <span v-else-if="e.job == 5">咨询师</span>
    <span v-else>其它</span>

    <!-- 使用 v-show: 基于CSS样式display来控制显示与隐藏 -->
    <!-- <span v-show="e.job == 1">班主任</span>
    <span v-show="e.job == 2">讲师</span>
    <span v-show="e.job == 3">学工主管</span>
    <span v-show="e.job == 4">教研主管</span>
    <span v-show="e.job == 5">咨询师</span> -->
</td>
  • 效果:
微信截图_20250710000339
  • 在使用 v-if 的时候:
微信截图_20250710000219
  • 在使用 v-show 的时候:
微信截图_20250710000320

3.5 v-model


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

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

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

    视图中的输入的数据变化,也会影响 Vue 的数据模型 。

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


2a91b7d0-397a-4543-91be-3053af37ef1e
  • 为员工列表案例的搜索栏的表单项,绑定数据:
html
<!-- 搜索表单区域 -->
<form class="search-form" action="#" method="post">
    <!-- 1.姓名区域 添加v-model -->
    <input type="text" name="name" placeholder="姓名" v-model="searchForm.name"/>
    <!-- 2.性别区域 添加v-model -->
    <select name="gender" v-model="searchForm.gender">
        <option value="">性别</option>
        <option value="1">男</option>
        <option value="2">女</option>
    </select>
    <!-- 3.职位区域 添加v-model -->
    <select name="job" v-model="searchForm.job">
        <option value="">职位</option>
        <option value="1">班主任</option>
        <option value="2">讲师</option>
        <option value="3">学工主管</option>
        <option value="4">教研主管</option>
        <option value="5">咨询师</option>
    </select>
    <button type="button" @click="search">查询</button>
    <button type="button" class="clear" @click="clear">清空</button>
</form>
html
<script type="module">
    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'

    createApp({
        data() {
            return {

                //定义数据模型,采集员工搜索表单数据
                searchForm:{
                    name:"",
                    gender:"",
                    job:""
                },


                empList: [
                    { "id": 1,
                     "name": "谢逊",
                     "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
                     "gender": 1,
                     "job": "1",
                     "entrydate": "2023-06-09",
                     "updatetime": "2024-07-30T14:59:38"
                    },
                    {
                        "id": 2,
                        "name": "韦一笑",
                        "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
                        "gender": 1,
                        "job": "1",
                        "entrydate": "2020-05-09",
                        "updatetime": "2023-07-01T00:00:00"
                    },
                    {
                        "id": 3,
                        "name": "黛绮丝",
                        "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
                        "gender": 2,
                        "job": "2",
                        "entrydate": "2021-06-01",
                        "updatetime": "2023-07-01T00:00:00"
                    }
                ]
            }
        },
		
    }).mount('#container')
</script>

3.6 v-on


  • 作用:为 html 标签绑定事件(添加时间监听)
  • 语法:
    • v-on:事件名="方法名"
    • 简写:@事件名="…"
html
<!-- v-on -->
<input type="button" value="点我一下试试" v-on:click="handle">
<!-- @ 简写 -->
<input type="button" value="点我一下试试" @click="handle">

  • 这里的 handle 函数,就需要在 Vue 应用实例创建的时候创建出来,在 methods 定义。
bd7ee3a8-afcc-4e32-a9df-12844ce80c4b
  • 为员工列表案例的搜索栏中的查询 和 清空按钮绑定事件:
html
<button type="button" @click="search">查询</button>
<button type="button" class="clear" @click="clear">清空</button>
html
<script type="module">
    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'

    createApp({
        data() {
            return {

                //定义数据模型,采集员工搜索表单数据
                searchForm:{
                    name:"",
                    gender:"",
                    job:""
                },


                empList: [
                    { "id": 1,
                     "name": "谢逊",
                     "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/4.jpg",
                     "gender": 1,
                     "job": "1",
                     "entrydate": "2023-06-09",
                     "updatetime": "2024-07-30T14:59:38"
                    },
                    {
                        "id": 2,
                        "name": "韦一笑",
                        "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg",
                        "gender": 1,
                        "job": "1",
                        "entrydate": "2020-05-09",
                        "updatetime": "2023-07-01T00:00:00"
                    },
                    {
                        "id": 3,
                        "name": "黛绮丝",
                        "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/2.jpg",
                        "gender": 2,
                        "job": "2",
                        "entrydate": "2021-06-01",
                        "updatetime": "2023-07-01T00:00:00"
                    }
                ]
            }
        },
		
        // 方法:
        methods: { 
            search() {
                console.log(this.searchForm)
            },
            clear() {
                this.searchForm = {
                    name: '',
                    gender: '',
                    job: ''
                }
            }
        }
    }).mount('#container')
</script>
  • 注意: methods 函数中的 this 指向 Vue 实例,可以通过 this 获取到 data 中定义的数据。

3.7 Vue 调试工具


b10f7381-080e-4679-8ea0-97022a2a9607
  • 下载后解压出 .crx 后缀的文件
  • 打开谷歌的 管理扩展程序
Snipaste_2025-07-10_02-29-07
  • 拖拽 .crx 后缀文件进去浏览器页面
  • 打开下面的这个选项
微信截图_20250710023030
  • F12 里面使用
微信截图_20250710023155

四、Ajax & Axios


4.0 异步请求地址


txt
Ajax演示:

	GET请求:  https://mock.apifox.cn/m1/3083103-0-default/emps/list
	
	POST请求: https://mock.apifox.cn/m1/3083103-0-default/emps/update



Ajax员工列表案例地址:
	
	https://web-server.itheima.net/emps/list
	
	https://web-server.itheima.net/emps/list?name=xxx&gender=xxx&job=xxx

4.1 概述


我们前端页面中的数据,如下图所示的表格中的员工信息,应该来自于后台,

那么我们的后台和前端是互不影响的 2 个程序,那么我们前端应该如何从后台获取数据呢?

因为是2个程序,所以必须涉及到2个程序的交互,所以这就需要用到我们接下来学习的 Ajax 技术。


0f044f02-0356-4b4b-b202-2a30bf0add64
  • Ajax : 全称 Asynchronous JavaScript And XML异步的 JavaScript 和 XML

  • XML:(英语:Extensible Markup Language)可扩展标记语言,

    本质是一种数据格式,可以用来存储复杂的数据结构。


    Ajax 作用有如下 2 点 :

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

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

      如:搜索联想、用户名是否可用的校验等等。


  • 详细解释一下这两点作用:


    • 与服务器进行数据交互

      • 如下图所示前端资源被浏览器解析,但是前端页面上缺少数据,前端可以通过 Ajax 技术,

        向后台服务器发起请求,后台服务器接受到前端的请求,从数据库中获取前端需要的资源,

        然后响应给前端,前端在通过我们学习的 vue 技术,可以将数据展示到页面上,

        这样用户就能看到完整的页面了。此处可以对比 JavaSE 中的网络编程技术来理解

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

      • 如下图所示,当我们再百度搜索 java 时,下面的联想数据是通过 Ajax 请求从后台服务器得到的,

        在整个过程中,我们的 Ajax 请求不会导致整个百度页面的重新加载,

        并且只针对搜索栏这局部模块的数据进行了数据的更新,

        不会对整个页面的其他地方进行数据的更新,这样就大大提升了页面的加载速度,用户体验高。

    96dce349-59df-44f1-a3f3-025a6e414650

补充:同步异步是什么??


针对于上述 Ajax 的局部刷新功能是因为 Ajax 请求是异步的,与之对应的有同步请求


  • 同步请求如下图所示:
0f044f02-0356-4b4b-b202-2a30bf0add65

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

只能等到服务器响应结束后才能,浏览器页面才能继续做其他的操作。


  • 异步请求如下图所示:
adc6c826-c48d-48df-b28e-24792034f1b5

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


4.2 Axios


使用原生的 Ajax 请求的代码编写起来还是比较繁琐的,

所以接下来我们学习一门更加简单的发送 Ajax 请求的技术Axios 。

Axios是对原生的 AJAX 进行封装,简化书写。

  • Axios 官网是:https://www.axios-http.cn

a31abb0d-0be9-4d4e-940e-63af75c564ea

4.2.1 入门程序


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


    • 1). 引入 Axios 文件(如果网络不通畅,可以使用离线的已经下载好的 js 文件,下面网盘链接已提供):
    html
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    txt
    通过网盘分享的文件:axios.js
    链接: https://pan.baidu.com/s/1ELaOyyT_jF6RShFMa2eXdQ?pwd=y2h8 提取码: y2h8

    • 2). 点击按钮时,使用 Axios 发送请求
    html
    <body>
    
        <button id="getData">发起 GET 请求</button>
        <button id="postData">发起 POST 请求</button>
    
    
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <script>
            
            //GET请求
            document.querySelector('#getData').onclick = function() {
                axios({
                    url:'https://mock.apifox.cn/m1/3083103-0-default/emps/list',
                    method:'get'
                }).then(function(res) {
                    console.log(res.data);
                }).catch(function(err) {
                    console.log(err);
                })
            }
            
            //POST请求
            document.querySelector('#postData').onclick = function() {
                axios({
                    url:'https://mock.apifox.cn/m1/3083103-0-default/emps/update',
                    method:'post',
                    data:"id=1" //POST请求体
                }).then(function(res) {
                    console.log(res.data);
                }).catch(function(err) {
                    console.log(err);
                })
            }
            
      </script>
        
    </body>

    微信截图_20250711005850

4.2.2 请求方式别名


  • 为了方便起见,Axios 已经为所有支持的请求方法提供了别名
  • 格式 : axios.请求方式(url[,data[,config]])

  • 所以在上述的入门案例中,我们可以将 get 请求代码改写成如下:
js
//GET请求
document.querySelector('#getData').onclick = function() {
    axios.get("https://mock.apifox.cn/m1/3083103-0-default/emps/list")
        .then((result) => {
        console.log(result.data.data);
    }).catch((err) => {
        console.log(err);
    });
}

  • post 请求改写成如下:
js
//POST请求
document.querySelector('#postData').onclick = function() {
    axios.post("https://mock.apifox.cn/m1/3083103-0-default/emps/update","id=1")
        .then((result) => {
        console.log(result.data);
    }).catch((err) => {
        console.log(err);
    });
}

补充 : 在使用 axios 时,在 axios 之后,输入 thenc 然后 Tab 键会自动生成成功及失败回调函数结构 。


4.2.3 案例:异步获取数据


需求:基于 axios 动态加载员工列表数据


  • 示例代码:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tlias智能学习辅助系统</title>
    <style>
      body {
        margin: 0;
      }

      /* 顶栏样式 */
      .header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        background-color: #c2c0c0;
        padding: 20px 20px;
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
      }
      
      /* 加大加粗标题 */
      .header h1 {
        margin: 0;
        font-size: 24px;
        font-weight: bold;
      }

      /* 文本链接样式 */
      .header a {
        text-decoration: none;
        color: #333;
        font-size: 16px;
      }

      /* 搜索表单区域 */
      .search-form {
        display: flex;
        align-items: center;
        padding: 20px;
        background-color: #f9f9f9;
      }

      /* 表单控件样式 */
      .search-form input[type="text"], .search-form select {
        margin-right: 10px;
        padding: 10px 10px;
        border: 1px solid #ccc;
        border-radius: 4px;
        width: 26%;
      }

      /* 按钮样式 */
      .search-form button {
        padding: 10px 15px;
        margin-left: 10px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 4px;
        cursor: pointer;
      }

      /* 清空按钮样式 */
      .search-form button.clear {
        background-color: #6c757d;
      }

      .table {
         min-width: 100%; 
         border-collapse: collapse;
      }

      /* 设置表格单元格边框 */
      .table td, .table th { 
        border: 1px solid #ddd; 
        padding: 8px; 
        text-align: center;
      }
      
      .avatar { 
        width: 30px; 
        height: 30px; 
        object-fit: cover; 
        border-radius: 50%; 
      }

      /* 页脚版权区域 */
    .footer {
        background-color: #c2c0c0;
        color: white;
        text-align: center;
        padding: 10px 0;
        margin-top: 30px;
    }

    .footer .company-name {
        font-size: 1.1em;
        font-weight: bold;
    }

    .footer .copyright {
        font-size: 0.9em;
    }

    #container {
      width: 80%;
      margin: 0 auto;
    }
    </style>
</head>
<body>
    
  <div id="container">
    <!-- 顶栏 -->
    <div class="header">
      <h1>Tlias智能学习辅助系统</h1>
      <a href="#">退出登录</a>
    </div>

    <!-- 搜索表单区域 -->
    <form class="search-form" action="#" method="post">
      <input type="text" name="name" placeholder="姓名" v-model="searchForm.name"/>
      <select name="gender" v-model="searchForm.gender">
          <option value="">性别</option>
          <option value="1">男</option>
          <option value="2">女</option>
      </select>
      <select name="job" v-model="searchForm.job">
          <option value="">职位</option>
          <option value="1">班主任</option>
          <option value="2">讲师</option>
          <option value="3">学工主管</option>
          <option value="4">教研主管</option>
          <option value="5">咨询师</option>
      </select>
      <button type="button" @click="search">查询</button>
      <button type="button" class="clear" @click="clear">清空</button>
    </form>

    <table class="table table-striped table-bordered">
      <thead>
          <tr>
            <th>序号</th>
            <th>姓名</th>
            <th>性别</th>
            <th>头像</th>
            <th>职位</th>
            <th>入职日期</th>
            <th>最后操作时间</th>
            <th>操作</th>
          </tr>
      </thead>
      <tbody>
            
        <tr v-for="(e, index) in empList" :key="e.id">
            <td>{{index + 1}}</td>
            <td>{{e.name}}</td>
            <td>{{e.gender == 1 ? "男":"女"}}</td>

            <td><img class="avatar" v-bind:src="e.image" :alt="e.image"></td>
            
            <td>
                <!-- 使用 v-if: 基于条件判断,来控制创建或移除元素节点(条件渲染) -->
                <span v-if="e.job == 1">班主任</span>
                <span v-else-if="e.job == 2">讲师</span>
                <span v-else-if="e.job == 3">学工主管</span>
                <span v-else-if="e.job == 4">教研主管</span>
                <span v-else-if="e.job == 5">咨询师</span>
                <span v-else>其他</span>

                <!-- 使用 v-show: 基于CSS样式display来控制显示与隐藏 -->
                <!-- <span v-show="e.job == 1">班主任</span>
                <span v-show="e.job == 2">讲师</span>
                <span v-show="e.job == 3">学工主管</span>
                <span v-show="e.job == 4">教研主管</span>
                <span v-show="e.job == 5">咨询师</span> -->
            </td>

            <td>{{e.entrydate}}</td>
            <td>{{e.updatetime}}</td>
            <td class="btn-group">
                <button class="edit">编辑</button>
                <button class="delete">删除</button>
            </td>
        </tr>
        
      </tbody>

    </table>

    <!-- 页脚版权区域 -->
    <footer class="footer">
      <p class="company-name">江苏传智播客教育科技股份有限公司</p>
      <p class="copyright">版权所有 Copyright 2006-2024 All Rights Reserved</p>
    </footer>

    <!-- 导入axios -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script type="module">
      import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'

        createApp({
            data() {
                return {

                    //定义数据模型,采集员工搜索表单数据
                    searchForm:{
                        name:"",
                        gender:"",
                        job:""
                    },

                    //清空empList,通过异步请求数据
                    empList: [] 
                }
            },

            //方法:
            methods: {
                //基于 axios 发送异步请求
                search() { 
                    axios.get(`https://web-server.itheima.net/emps/list?name=${this.searchForm.name}&gender=${this.searchForm.gender}&job=${this.searchForm.job}`) 
                    .then((result) => {
                        this.empList = result.data.data
                    }).catch((err) => {
                        alert(err)
                    });
                },
                clear() {
                        this.searchForm = {
                        name: '',
                        gender: '',
                        job: ''
                    }
                }
            }
        }).mount('#container')
    </script>

  </div>

</body>
</html>
  • 现在这版代码就可以在查找栏输入关键词去查找特定的员工信息了
  • 但是还有欠缺的部分,后面再补充 ...

4.2.4 async & await


  • 如果使用 axios 中提供的 .then(function(){....}).catch(function(){....})

    这种回调函数的写法,会使得代码的可读性和维护性变差。 而为了解决这个问题,

    我们可以使用两个关键字,分别是:async、await

  • 可以通过 asyncawait 可以 让异步变为同步操作

    async 就是来声明一个异步方法,await 是用来等待异步任务执行。


  • 代码修改前:
js
//基于 axios 发送异步请求
    search() {
        axios.get(`https://web-server.itheima.net/emps/list?name=${this.searchForm.name}&gender=${this.searchForm.gender}&job=${this.searchForm.job}`)
    .then((result) => {
    	this.empList = result.data.data
    }).catch((err) => {
    	alert(err)
    });
}

  • 代码修改后
js
//使用 async 关键字声明是异步方法
async search() {
   
   //使用 await 使得在异步方法内等待该方法执行完再执行后续代码(局部同步)
   const res = await axios.get(`https://web-server.itheima.net/emps/list?name=${this.searchForm.name}&gender=${this.searchForm.gender}&job=${this.searchForm.job}`)
   //获取 返回来的数据赋值给 res 再赋值去 this.empList
   this.empList = res.data.data
}
  • 修改后,代码就变成同步操作了,一行一行的从前往后执行。

    在前端项目开发中,经常使用这两个关键字配合,使得代码的可读性和可维护性变高。


五、Vue の 生命周期


5.1 介绍


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

  • vue 的生命周期包含 8 个阶段:每触发一个生命周期事件,会自动执行一个生命周期方法,

    这些生命周期方法也被称为 钩子方法 。其完整的生命周期如下表所示:

状态阶段周期
beforeCreate创建前
created创建后
beforeMount挂载前
mounted挂载完成
beforeUpdate更新前
updated更新后
beforeDestory销毁前
destroyed销毁后
  • 下图是 Vue 官网提供的从创建 Vue 到效果 Vue 对象的整个过程及各个阶段对应的钩子函数:
19ece700-8f2c-4e21-ba6a-4d4ad95c1914

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

mounted:挂载完成,Vue 初始化成功,HTML 页面渲染成功。

以后我们一般用于页面初始化自动的 ajax 请求后台数据


5.2 案例完善


html
<!-- 导入axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="module">
    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'

    createApp({
        data() {
            return {

                //定义数据模型,采集员工搜索表单数据
                searchForm:{
                    name:"",
                    gender:"",
                    job:""
                },

                //清空empList,通过异步请求数据
                empList: []
            }
        },

        //方法:
        methods: {
            //使用 async 关键字声明是异步方法
            async search() {
                //使用 await 使得在异步方法内等待该方法执行完再执行后续代码(局部同步)
                const res = await axios.get(`https://web-server.itheima.net/emps/list?name=${this.searchForm.name}&gender=${this.searchForm.gender}&job=${this.searchForm.job}`)
                this.empList = res.data.data
            },
            clear() {
                this.searchForm = {
                    name: '',
                    gender: '',
                    job: ''
                }
                //清空后不但清空查找栏,还需要调用一次search(),更新下面的表格信息
                this.search() 
            }
        },
        //挂载完成后search()一次,完成页面的初始化
        mounted(){ 
            this.search()
        }

    }).mount('#container')
</script>

微信截图_20250822134409

在挂载完成后 search() 一次请求到数据,完成页面的初始化,就完成了我们上面的基础的案例。


六、Vue 工程化


ba5f1cbb-69e5-45dc-8e44-74480db775f7

在前面我们学习了 Vue 的基本语法、表达式、指令,并基于 Vue 的核心包,完成了 Vue 的案例.

但这只是使用 Vue 进行前端的局部模块的改造,我们的目的是使用 Vue 来进行整站开发。


6.1 介绍


在前面的课程中,我们学习了 HTML、CSS、JS、Axios、Vue 等技术,并基于完成了一些前端开发的案例 。

我们目前的前端开发中,当我们需要使用一些资源时,例如:vue.js,和 axios.js 文件,

都是直接再工程中导入的,如下图所示:

bdbb3ba8-accc-4cb7-94a5-b8859f48a744

但是上述开发模式存在如下问题:

  • 不规范:每次开发都是从零开始,比较麻烦
  • 难复用:多个页面中的组件共用性不好
  • 难维护:js、图片等资源没有规范化的存储目录,没有统一的标准,不方便维护

所以现在企业开发中更加讲究前端工程化方式的开发,主要包括如下 4 个特点 :

c7e36852-735d-49ed-ab51-294046c0412f
  • 模块化:将 js 和 css 等,做成一个个可复用模块
  • 组件化:我们将 UI 组件,css 样式,js 行为封装成一个个的组件,便于管理
  • 规范化:我们提供一套标准的规范的目录接口和编码规范,所有开发人员遵循这套规范
  • 自动化:项目的构建,测试,部署全部都是自动完成

所以对于前端工程化,说白了,就是在企业级的前端项目开发中,把前端开发所需要的工具、技术、流程、

经验进行规范化和标准化。从而统一开发规范、提升开发效率,降低开发难度、提高复用等等。

接下来我们就需要学习 vue 的官方提供的脚手架帮我们完成前端的工程化。


6.2 环境准备


6.2.1 介绍


  • create-vue 是 Vue 官方提供的最新的脚手架工具,用于快速生成一个工程化的 Vue 项目。

  • create-vue 提供了如下功能:

    • 统一的目录结构
    • 本地调试
    • 热部署
    • 单元测试
    • 集成打包上线
  • 而要想使用 create-vue 来创建 vue 项目,则必须安装依赖环境:NodeJS

3c4e9867-6ad0-47f9-811f-d9c205b8a1bd

6.2.2 Nodejs 安装


如下网盘链接提供 NodeJS 安装包:

txt
通过网盘分享的文件:node-v18.20.4-x64.msi
链接: https://pan.baidu.com/s/127Ut5GL8_8eS90y6ui0jUw?pwd=e4iv 提取码: e4iv
86e48532-9707-4dea-b56b-ec3cd1769634
  • 1). 双击 msi 文件,勾选我接受
6e5cb5b2-ba7e-4903-ae84-956c0c9acd64
  • 2). 选择安装到一个,没有中文,没有空格 的目录下(新建一个文件夹 NodeJS
ef2962e2-2434-4c4a-9b8d-6d67eb948060
  • 3). 点击 Next,下一步下一步的安装即可。
f08f8395-59b4-4e68-887f-4155735941f7
  • 4). 验证 NodeJS 的环境变量

NodeJS 安装完毕后,会自动配置好环境变量,我们验证一下是否安装成功,通过: node -v

b2776282-802b-4022-a47e-a1010394e391
  • 5). 配置 npm 的全局安装路径
    • 后面需要用 npm install 安装软件包,这样可以指定安装目录
      • 避免占用系统盘空间(全局包可能很多很大)
      • 方便管理(比如 Node.js 安装在 D:\develop\Nodejs,全局包也放在一起)
6c25877e-b809-411e-addb-4d4273b627d4

使用 管理员身份 运行命令行,在命令行中,执行如下指令:

shell
npm config set prefix "D:\develop\NodeJS"

可以命令行运行以下命令查看有没有配置好:

shell
npm config get prefix

此外可以随便安装一个工具 nodemon

shell
npm install -g nodemon

如果在文件管理器找得到 D:\develop\Nodejs\node_modules\nodemon 就说明没问题


❗ 注意:

注意:D:\develop\NodeJS 这个目录是 NodeJS 的安装目录 !!!!! 换成自己实际的 !!!

注意:D:\develop\NodeJS 这个目录是 NodeJS 的安装目录 !!!!! 换成自己实际的 !!!

注意:D:\develop\NodeJS 这个目录是 NodeJS 的安装目录 !!!!! 换成自己实际的 !!!


  • 6). 切换为淘宝镜像,加速下载:
shell
npm config set registry https://registry.npmmirror.com

6.2.3 npm 介绍


  • npmNode Package Manager,是 NodeJS 的软件包管理器。
75a47f34-f887-40e0-85b7-1b807799a123

在开发前端项目的过程中,我们需要相关的依赖,就可以直接通过 npm install xxx 命令,

直接从远程仓库中将依赖直接下载到本地了。


6.3 Vue 项目创建


6.3.1 项目创建


  • ❗ 选定一个空文件夹,创建一个工程化的 Vue 项目,执行命令:npm create vue@3.3.4
981ac4aa-b4e3-4e03-b141-76470fd2dcd4

📌 详细说明:

  • Project name:------------------》项目名称,默认值:vue-project,可输入想要的项目名称。
  • Add TypeScript? ----------------》是否加入 TypeScript 组件?默认值:No。
  • Add JSX Support? --------------》是否加入 JSX 支持?默认值:No。
  • Add Vue Router...--------------》是否为单页应用程序开发添加 Vue Router 路由管理组件?默认值:No。
  • Add Pinia ...----------------------》是否添加 Pinia 组件来进行状态管理?默认值:No。
  • Add Vitest ...---------------------》是否添加 Vitest 来进行单元测试?默认值:No。
  • Add an End-to-End ...-----------》是否添加端到端测试?默认值 No。
  • Add ESLint for code quality? ---》是否添加 ESLint 来进行代码质量检查?默认值:No。

📌 执行上述指令,将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具


  • 项目创建完成以后,cd vue-project01 进入 vue-project01 项目目录,

  • 执行命令安装当前项目的依赖:npm install

1d734abf-b171-4088-979e-bf1028307766

📌 创建项目以及安装依赖的过程,都是需要联网的。【如果网络不太好,可能会造成依赖下载不完整报错,继续再次执行 命令安装。】


6.3.2 项目结构


我们可以使用 VsCode 直接打开这个 Vue 项目。

778a136c-e0d5-4a56-be12-a48b6d2591d1

这是我们创建的第一个项目结构,接下来呢,我们来介绍一下这个项目的结构。如图所示:

fd8b2cc9-bdad-4821-ae0d-f6c492da6be1

在上述的目录中,我们以后操作的最多的目录,就是 src 目录,因为我们需要在这个目录下来编写前端代码。


6.3.3 启动项目


  • 方式一:命令行

启动项目,我们可以在命令行中执行命令:npm run dev,就可以启动 Vue 项目了。

5e93de97-28d8-49c4-9616-f0cc883ef40d
  • 方式二:Vscode 图形化界面

点击 NPM 脚本中的 dev 后的运行按钮,就可以启动项目。

fc283bcb-b7a5-4511-ac09-6279930ad8f4

6.3.4 VSCode 常见问题


  • 先补充一下:

    • 在项目路径下打开终端:(后面 npm install 的时候需要用到)
    微信截图_20250825011557
    • 打开终端窗口(有时候终端挡着空间,关掉后想再打开):
    Snipaste_2025-08-25_01-17-23

  • 问题一:没有显示 NPM脚本

如果说 VSCode 没有如下 NPM脚本 的显示:

微信截图_20250825002601

那么做如下操作:

微信截图_20250825002721
  • 问题二:VSCode 没有 powershell 权限:

  • 首先我们可以改变默认终端为 cmd :

    • 方法一如下图:
    微信截图_20250825011205
    • 方法二:
      • Ctrl + Shift + P
      • 输入并选择 Terminal: Select Default Profile
      • 在弹出的列表里 选 Command Prompt

  • 方法二:改变 powershell 执行策略 :

当我们点击 NPM 脚本中的 dev 后的运行按钮,如果说它默认给我们打开的是 powershell

而不是 cmd 窗口的话,那么 Windows PowerShell 默认执行策略为 Restricted,拒绝任何 .ps1 脚本运行。

就会遇到如下报错:

微信截图_20250825003034
  • 那么我们只需要把策略放宽即可:在电脑上使用 管理员权限打开 powershell :
微信截图_20250825003218
  • 执行命令(仅影响当前用户,安全级别适中)
powershell
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
  • 出现提示时输入 Y 回车确认。

  • 验证是否成功
powershell
Get-ExecutionPolicy
  • 应返回 RemoteSigned

策略值含义安全性
Restricted默认,禁止所有脚本
RemoteSigned本地脚本可直接运行,远程脚本需签名
Bypass完全放行,无提示

  • 所以其实刚刚我们一连串的操作,是把策略 Restricted 改成了 RemoteSigned

这样就可以正常执行了:

微信截图_20250825004103

启动起来之后,我们就可以访问前端 Vue 项目了,访问路径:http://localhost:5173

5e92cd20-af28-48f4-980f-65c4e99150b6

6.4 项目开发流程


如下图:

15f18950-aa53-4ff4-b4a8-6816c165c946

其中*.vue 是 Vue 项目中的组件文件,在 Vue 项目中也称为单文件组件(SFC,Single-File Components)。

Vue 的单文件组件会将一个组件的 逻辑 (JS),模板 (HTML) 和样式 (CSS) 封装在同一个文件里(*.vue

686233dc-b59e-4ed2-9d26-618192c0fbf2

6.5 API 风格


  • Vue 的组件有两种不同的风格:组合式 API选项式 API

  • 组合式API:是 Vue3 提供的一种基于函数的组件编写方式,通过使用函数来组织和复用组件的逻辑。

    它提供了一种更灵活、更可组合的方式来编写组件。代码形式如下:

vue
<script setup>
import { ref, onMounted } from 'vue';
const count = ref(0); //声明响应式变量

function increment(){ //声明函数
   count.value++;
}

onMounted(() => { //声明钩子函数
  console.log('Vue Mounted....'); 
})
</script>

<template>
   <input type="button" @click="increment"> Api Demo1 Count : {{ count }}
</template>

<style scoped>
   
</style>

📌 说明:

  • setup:是一个标识,告诉 Vue 需要进行一些处理,让我们可以更简洁的使用组合式 API。
  • ref():接收一个内部值,返回一个响应式的 ref 对象,此对象只有一个指向内部值的属性 value
  • onMounted():在组合式 API 中的钩子方法,注册一个回调函数,在组件挂载完成后执行。

  • 官方说明:
微信截图_20250822145045
  • 而且补充一句:在工程化之前,可以发现,我们的风格写的就是 选项式 API

  • 选项式 API

    • 可以用包含多个选项的对象来描述组件的逻辑,如:datamethodsmounted等。

      选项定义的属性都会暴露在函数内部的this上,它会指向当前的组件实例。

vue
<script>
export default{
   data() {
      return {
         count: 0
      }
   },
   methods: {
      increment: function(){
         this.count++
      }
   },
   mounted() {
      console.log('vue mounted.....');
   }
}
</script>

<template>
  <input type="button" @click="increment">Api Demo1 Count :  {{ count }}
</template>

<style scoped>

</style>

📌 在 Vue 中的组合式 API 使用时,是没有 this 对象的,this 对象是 undefined


6.6 案例


在 Vue 项目中,基于组合式 API 完成用户列表数据渲染。

要求:在页面加载完毕之后,发送异步请求,加载数据,渲染表格。

最终实现效果:

c55a9682-5a73-4543-88bb-d3632b7a1a41
  • 代码实现:

src 下定义 views 目录,在 views 目录中定义文件 UserList.vue

然后,我们就可以将之前(第一到五章)实现的 Vue 案例中的代码,基于 Vue 工程化 的形式来实现一遍。

之前实现的这个页面,如下代码块提供:

html
<!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>Vue3-案例1</title>
  <style>
    table,th,td {
      border: 1px solid #000;
      border-collapse: collapse;
      line-height: 50px;
      text-align: center;
    }

    #center,table {
      width: 60%;
      margin: auto;
    }

    #center {
      margin-bottom: 20px;
    }

    img {
      width: 50px;
    }

    input,select {
      width: 17%;
      padding: 10px;
      margin-right: 30px;
      border: 1px solid #ccc;
      border-radius: 4px;
    }

    .btn {
      background-color: #ccc;
    }
  </style>
</head>

<body>
  <div id="app">

    <div id="center">
      姓名: <input type="text" name="name" v-model="name">

      性别:
      <select name="gender" v-model="gender">
        <option value="1">男</option>
        <option value="2">女</option>
      </select>

      职位:
      <select name="job" v-model="job">
        <option value="1">班主任</option>
        <option value="2">讲师</option>
        <option value="3">其他</option>
      </select>

      <input class="btn" type="button" value="查询" @click="search">
    </div>
    
    <table>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>头像</th>
        <th>性别</th>
        <th>职位</th>
        <th>入职时间</th>
        <th>更新时间</th>
      </tr>

      <!-- v-for 用于列表循环渲染元素 -->
      <tr v-for="(user, index) in userList" :key="user.id">
        <td>{{index + 1}}</td>
        <td>{{user.name}}</td>
        <td> <img :src="user.image"> </td>
        <td>
          <span v-if="user.gender == 1">男</span>
          <span v-else-if="user.gender == 2">女</span>
          <span v-else>其他</span>
        </td>
        <td>
          <span v-show="user.job == 1">班主任</span>
          <span v-show="user.job == 2">讲师</span>
          <span v-show="user.job != 1 && user.job != 2">其他</span>
        </td>
        <td>{{user.entrydate}}</td>
        <td>{{user.updatetime}}</td>
      </tr>
    </table>
    
  </div>

  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script type="module">
    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
    createApp({
      data() {
        return {
          name:'',
          gender:'',
          job:'',
          userList: []
        }
      },
      methods: {
        search(){
          //基于axios发送异步请求加载数据
          axios.get(`https://web-server.itheima.net/emps/list?name=${this.name}&gender=${this.gender}&job=${this.job}`).then((result) => {
            console.log(result);
            this.userList = result.data.data;
          })
        }
      },
      //定义一个钩子函数 mounted
      mounted() {
        //页面加载完毕之后, 自动调用search
        this.search();
      }
    }).mount("#app");
  </script>
</body>

</html>

  • 把原来定义的 CSS 样式代码,拷贝到 <style></style> 标签中。

  • 把页面的 <div id="app"></div> 中的页面展示的 html 标签代码,

    拷贝到 <template></template> 标签中。

  • 将页面的 JS 代码,按照组合式 API 的形式,在 <script></script> 中定义出来。

    • 其中项目中用到 axios , 需要安装 axios 的依赖 npm install axios
  • 而由于在这个案例中,需要用到 axios 来发送异步请求,所以还需要安装 axios


  • 修改后代码如下:
  • views/UserList.vue 代码如下:
vue
<script setup>
//引入ref
import { ref, onMounted } from 'vue';
import axios from 'axios';

//声明响应式数据 userList, name, gender, job
const userList = ref([]);
const name = ref('');
const gender = ref('');
const job = ref('');

//声明函数,基于axios查询数据
const search = async () => {
  //基于axios发送异步请求加载数据
  const result = await axios.get(`https://web-server.itheima.net/emps/list?name=${name.value}&gender=${gender.value}&job=${job.value}`);
  //将查询到的数据赋值给userList
  userList.value = res.data.data;
  
}

//定义钩子函数 onMounted
onMounted(() => {
  //调用search函数
  search();
})
</script>

<template>
  <div id="center">
    姓名: <input type="text" name="name" v-model="name">

    性别:
    <select name="gender" v-model="gender">
      <option value="1">男</option>
      <option value="2">女</option>
    </select>

    职位:
    <select name="job" v-model="job">
      <option value="1">班主任</option>
      <option value="2">讲师</option>
      <option value="3">其他</option>
    </select>

    <input class="btn" type="button" value="查询" @click="search">
  </div>
  
  <table>
    <tr>
      <th>序号</th>
      <th>姓名</th>
      <th>头像</th>
      <th>性别</th>
      <th>职位</th>
      <th>入职时间</th>
      <th>更新时间</th>
    </tr>

    <!-- v-for 用于列表循环渲染元素 -->
    <tr v-for="(user, index) in userList" :key="user.id">
      <td>{{index + 1}}</td>
      <td>{{user.name}}</td>
      <td> <img :src="user.image"> </td>
      <td>
        <span v-if="user.gender == 1">男</span>
        <span v-else-if="user.gender == 2">女</span>
        <span v-else>其他</span>
      </td>
      <td>
        <span v-show="user.job == 1">班主任</span>
        <span v-show="user.job == 2">讲师</span>
        <span v-show="user.job != 1 && user.job != 2">其他</span>
      </td>
      <td>{{user.entrydate}}</td>
      <td>{{user.updatetime}}</td>
    </tr>
  </table>
</template>

<style scoped>
  table,th,td {
    border: 1px solid #000;
    border-collapse: collapse;
    line-height: 50px;
    text-align: center;
  }

  #center,table {
    width: 60%;
    margin: auto;
  }

  #center {
    margin-bottom: 20px;
  }

  img {
    width: 50px;
  }

  input,select {
    width: 17%;
    padding: 10px;
    margin-right: 30px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }

  .btn {
    background-color: #ccc;
  }
</style>

❗ 注意:

import axios from 'axios' 这句代码不要加 {}axios


然后在 App.vue 中,将 UserList.vue 引入进来。

vue
<script setup>
import UserList from './views/UserList.vue'
</script>

<template>
   <UserList></UserList>
</template>

<style scoped>

</style>

最终展示形式如下:

cdf5fc31-7813-45ff-8a9b-bc7cd70d6fc0