Skip to content

前端 Web 实战(Vue 工程化 +ElementPlus)

Vue 工程化

前面我们在介绍 Vue 的时候,我们讲到 Vue 是一款用于构建用户界面的渐进式 JavaScript 框架 。(官方:https://cn.vuejs.org/

那在前面的课程中,我们已经学习了 Vue 的基本语法、表达式、指令,并基于 Vue 的核心包,完成了 Vue 的案例。 那今天呢,我们要来讲解的基于 Vue 进行整站开发。 - 上面的vuex webpack是vue2的,pinia vite都是vue3的.

介绍

在前面的课程中,我们学习了 HTML、CSS、JS、Axios、Vue 等技术,并基于完成了一些前端开发的案例 。我们目前的前端开发中,当我们需要使用一些资源时,例如:vue.js,和 axios.js 文件,都是直接在工程中导入的,如下图所示:

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

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

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

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

所以对于前端工程化,说白了,就是在企业级的前端项目开发中,把前端开发所需要的工具、技术、流程、经验进行规范化和标准化。从而统一开发规范、提升开发效率,降低开发难度、提高复用等等。接下来我们就需要学习 vue 的官方提供的脚手架帮我们完成前端的工程化。

环境准备

介绍

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

  • 统一的目录结构

  • 本地调试
  • 热部署
  • 单元测试
  • 集成打包上线
  • 而要想使用 create-vue 来创建 vue 项目,则必须安装依赖环境:NodeJS(这个环境类似于java的JVM/JDK)

NodeJS 安装

安装包,在课程资料中已经提供了。如下:

1). 双击 msi 文件,勾选我接受

2). 选择安装到一个,没有中文,没有空格 的目录下(新建一个文件夹 NodeJS)

3). 点击 Next,下一步下一步的安装即可。

4). 验证 NodeJS 的环境变量

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

5). 配置 npm 的全局安装路径

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

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

注意:D:\develop\NodeJS  这个目录是 NodeJS 的安装目录 !!!!!

注意:D:\develop\NodeJS  这个目录是 NodeJS 的安装目录 !!!!!

注意:D:\develop\NodeJS  这个目录是 NodeJS 的安装目录 !!!!!

6). 切换为淘宝镜像,加速下载:

npm config set registry https://registry.npmmirror.com

npm 介绍

  • npm:Node Package Manager,是 NodeJS 的软件包管理器。下载好了nodejs,会自动安装npm.其实很类似maven

在开发前端项目的过程中,我们需要相关的依赖,就可以直接通过 npm install xxx 命令,直接从远程仓库中将依赖直接下载到本地了。

Vue 项目创建

项目创建

创建一个工程化的 Vue 项目,执行命令:npm create vue@3.3.4 这个在第一次执行其实就是会自动安装并且执行create-vue这个脚手架工具的3.3.4版本.如果不添加版本号,那么就默认使用最新的.如果不是第一次,那么就不会自动安装,而是直接创建项目

详细步骤说明:

  • 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。

[!TIP] 提示:执行上述指令,将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具.

项目创建完成以后,进入 vue-project01 项目目录,执行命令安装当前项目的依赖:npm install

创建项目以及安装依赖的过程,都是需要联网的。【如果网络不太好,可能会造成依赖下载不完整报错,继续再次执行 命令安装。】 然后我们看一下这个目录: 可以看到,node_modules就是我们当前存放依赖的目录.

项目结构

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

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

在上述的目录中,我们以后操作的最多的目录,就是 src 目录,因为我们需要在这个目录下来编写前端代码。 - package.json就是类似于pom.xml. 一般来说,上面这个package.json最好打开一下,让vscode知道有哪些脚本(不然下面的"启动项目"里在vscode图形化界面里找不到"npm脚本")

启动项目

  • 方式一:命令行

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

  • 方式二:Vscode 图形化界面 注意勾选npm脚本 点击 NPM 脚本中的 dev 后的运行按钮,就可以启动项目。

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

Vue 项目开发流程

如下图:

- 其中第一个文件index.html就在根目录下. - createApp函数是来创建vue实例的,创建的应用实例挂载到一个css选择器(id选择器). - App是一个"组件".所有的数据就在这个组件当中,这个组件的内容也就是id为"app"的div区域当中. - 注意main.js里引入了一个main.css文件.

ps:原本我们是这样的:

其中 *.vue 是 Vue 项目中的组件文件,在 Vue 项目中也称为单文件组件(SFC,Single-File Components)。Vue 的单文件组件会将一个组件的逻辑 (JS),模板 (HTML) 和样式 (CSS) 封装在同一个文件里(*.vue

- 第一部分就是js,第二部分就是html,第三部分就是css样式. - 由于vue是数据驱动的,因此就上面的这种方式来定义数据模型.首先我们需要使用import一个ref函数.这个ref就是定义响应式数据的.所谓响应式数据,就是数据一旦更改,页面上的内容(视图)也会同步更改.声明响应式数据的定义方式就是上面所示.当然,如果我们声明的是变量,那么也可以使用let来定义. 我们可以通过安装的vue插件来自己修改数据: 点一下保存,页面也就会更新.

API 风格

  • Vue 的组件有两种不同的风格:组合式 API选项式 API
  • 组合式 API是 Vue3 提供的一种基于函数的组件编写方式,通过使用函数来组织和复用组件的逻辑。它提供了一种更灵活、更可组合的方式来编写组件。代码形式如下:

<script setup>//setup是一个标识,告诉vue需要进行一些处理,让我们可以更简洁的使用组合式api.
import { ref, onMounted } from 'vue';
const count = ref(0); //声明响应式变量,只需要通过ref即可.
//这个count是Ref<number,number>类型的响应式对象.响应式对象只有一个属性value,这个value才是我们真正存放数据的地方.
function increment(){ //声明函数
   count.value++;//组合式api当中,this的指向是undefined,所以我们不能通过this来访问响应式数据.而作为一个响应式对象,显然是不能直接++这样的自增操作的,而是要通过value属性来访问和修改数据.
}

onMounted(() => { //声明钩子函数.注意这里的名字和之后的选项式api不一样.组合式api中是onMounted,选项式api中是mounted,多了一个on.
  console.log('Vue Mounted....'); 
})
</script>

<template>
   <input type="button" @click="increment"> Api Demo1 Count : {{ count }}
</template>//@click是 v-on:click的缩写

<style scoped> // scoped表示这个css样式只作用于当前组件

</style>
上面这个内容我们往往会放到/src/views目录当中,比如创建一个ApiDemo.vue文件,然后把上面的代码放进去.然后在根组件当中引入: 这样更改之后不需要重启,因为工程化的vue会热部署,自动加载.

[!TIP]

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

选项式 API:可以用包含多个选项的对象来描述组件的逻辑,如:datamethodsmounted 等。选项定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。

<script>
export default{
   data() {
      return {
         count: 0
      }//这个返回值就是我们定义的响应式数据.
   },
   methods: {//声明方法,可以通过组件实例来访问.
      increment: function(){
         this.count++//通过this来控制响应式数据.
      }
   },
   mounted() {//钩子函数
      console.log('vue mounted.....');
   }
}
</script>

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

<style scoped>

</style>

[!TIP] 在 Vue 中的组合式 API 使用时,是没有 this 对象的,this 对象是 undefined。

案例

在 Vue 项目中,基于组合式 API 完成用户列表数据渲染。 要求:在页面加载完毕之后,发送异步请求,加载数据,渲染表格。

最终实现效果:

代码实现如下:

在 src 下定义 views 目录,在 views 目录中定义文件 UserList.vue, 然后,我们就可以将之前实现的 Vue 案例中的代码,基于 Vue 工程化的形式来实现一遍。 (之前实现的这个页面,在资料中已经提供了:1.工程化-案例-素材.html)

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

2). 把页面的 <div id="app"></div> 中的页面展示的 html 标签代码,拷贝到 <template></template> 标签中。

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

4). 而由于在这个案例中,需要用到 axios 来发送异步请求,所以还需要安装 axios

具体代码如下:

views/UserList.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 = () => {
  //发送请求
  axios.get(`https://web-server.itheima.net/emps/list?name=${name.value}&gender=${gender.value}&job=${job.value}`).then(res => {
    //将查询到的数据赋值给userList
    userList.value = res.data.data
  })
  //这里的异步意味着发送请求之后,会往下执行后面的内容(虽然这里后面也没有内容了),直到收到响应才会执行回调
}
//上面这个也能改成同步的风格:注意await必须加async
// const search = async () => {
//   const res = await axios.get(`https://web-server.itheima.net/emps/list?name=${name.value}&gender=${gender.value}&job=${job.value}`)
//   userList.value = res.data.data
// }//加了async后,search会在这里阻塞住,收到结果才会执行await后面的内容(虽然这里后面也没有内容了).而对于search的调用者,search会立即返回,不会等待search执行完成.
//定义钩子函数 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>

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

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

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

<style scoped>

</style>

最终展示形式如下:

ElementPlus

介绍

Element:是饿了么公司前端开发团队提供的一套基于 Vue3 的网站组件库,用于快速构建网页。

Element 提供了很多组件(组成网页的部件)供我们使用。例如 超链接、按钮、图片、表格等等。

官方网站:https://element-plus.org/zh-CN/#/zh-CN

如下图所示就是我们开发的页面和 ElementUI 提供的效果对比:可以发现 ElementUI 提供的各式各样好看的按钮。

ElementPlus 的学习方式和我们之前的学习方式不太一样,对于 ElementPlus,我们作为一个后台开发者,只需要学会如何从 ElementPlus 的官网拷贝组件到我们自己的页面中,并且做一些修改即可。 我们主要学习的是 ElementPlus 中提供的常用组件,至于其他组件同学们可以通过我们这几个组件的学习掌握到 ElementPlus 的学习技巧,然后课后自行学习。

快速入门

准备工作:

1). 将资料中提供的基础工程(资料/04. ElementPlus基础工程/vue-project02.zip),解压到工作目录中,使用 VSCode 将其打开。

2). 参照官方文档,安装 ElementPlus 的组件库(在当前工程的目录下),执行如下命令:【这一步可以不做,已经安装好了】

npm install element-plus@2.4.4 --save//--save表示将这个依赖写入package.json文件中

3). 在 main.js 中引入 ElementPlus 组件库 (参照官方文档),最终 main.js 中代码如下:

import { createApp } from 'vue'
import App from './App.vue'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)
app.use(ElementPlus)

app.mount('#app')//当然,实际上也是可以链式调用的:

制作组件:

1). 访问 ElementPlus 的官方文档,查看对应的组件源代码。

2). 在 src 下创建 views 目录,在 views 目录下,创建 Element.vue 组件文件,复制组件代码,调整成自己想要的 。

<script setup>

</script>

<template>
  <el-row class="mb-4">
    <el-button>Default</el-button>//默认按钮背景色是白色
    <el-button type="primary">Primary</el-button>//type设为primary,按钮背景色就是蓝色
    <el-button type="success">Success</el-button>//
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </el-row>
</template>

<style scoped>

</style>

3). 在根组件 app.vue 中引入 Element.vue

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

<template>
  <Element></Element>
</template>

<style scoped>

</style>

4). 启动项目,访问 http://localhost:5173

常见组件

表格组件

用于展示多条结构类似的数据, 可对数据进行排序、筛选、对比或其他自定义操作。

接下来我们通过代码来演示。

首先我们需要来到 ElementPlus 的组件库中,找到表格组件,如下图所示:

然后在 Element.vue 组件中继续制作表格。组件中,需要注意的是,我们组件包括了 3 个部分,如果官方有除了 <template> 部分之外的 <style><script> 都需要复制。具体操作如下图所示:

其中: 当 el-table 元素中注入 data 对象数组后,在 el-table-column中用prop 属性来对应对象中的键名即可填入数据,用label来定义表格的列名。可以使用 width 属性来定义列宽。 整体代码如下所示:

<script setup>
const tableData = [
  {date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-02', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-04', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-01', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'}
]
</script>

<template>

  <!-- Button按钮 -->
  <el-row class="mb-4">
    <el-button>Default</el-button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </el-row>

  <br>

  <!-- Table表格 -->
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address" //没有指定宽度,那么剩下的宽度都是address的宽度.
  </el-table>
</template>

<style scoped>

</style>
:data是v-bind的简写,表示将tableData这个变量绑定到data属性上. 此时回到浏览器,我们页面呈现如下效果:

[!TIP] Table 表格组件,属性说明:

  • data: 主要定义 table 组件的数据模型
  • prop: 定义列的数据应该绑定 data 中定义的具体的数据模型
  • label: 定义列的标题
  • width: 定义列的宽度

分页条组件

Pagination: 分页组件,主要提供分页工具条相关功能。其展示效果图下图所示:

最后一个All combined是最全的. 默认情况下,ElementPlus 的组件是英文的,如果希望使用中文语言,可以在 main.js 中做如下配置:

import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
app.use(ElementPlus, {locale: zhCn})

接下来我们通过代码来演示功能。

首先在官网找到分页组件,我们选择带背景色分页组件,如下图所示:

然后复制代码到我们的 Element.vue 组件文件的 template 中,在 <template> </template> 拷贝如下代码:

<el-pagination
    v-model:current-page="currentPage4"//currentPage4是我们定义的变量,表示当前页码,由于在下面的script中定义为4,因此初始显示第4页.
    v-model:page-size="pageSize4"//表示每页显示多少条数据,初始值为100
    :page-sizes="[100, 200, 300, 400]"//下拉列表里可以显示哪些值(可见上图那个可以下拉的框)
    layout="total, sizes, prev, pager, next, jumper"
    :total="400"//总的记录数.当然,这里也可以绑定一个声明变量
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />

<script> </script> 中拷贝如下代码:

import { ref } from 'vue'

const currentPage4 = ref(4)
const pageSize4 = ref(100)

const handleSizeChange = (val) => {
  console.log(`${val} items per page`)
}
const handleCurrentChange = (val) => {
  console.log(`current page: ${val}`)
}
ps:ts比js多了类型限制. 目前,整个 Element.vue 的文件内容如下(绿色背景部分代码为本次增加的代码):

<script setup>
import { ref } from 'vue'

const tableData = [
  {date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-02', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-04', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-01', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'}
]

const currentPage4 = ref(4)
const pageSize4 = ref(100)

const handleSizeChange = (val) => {
  console.log(`${val} items per page`)
}
const handleCurrentChange = (val) => {
  console.log(`current page: ${val}`)
}
</script>

<template>

  <!-- Button按钮 -->
  <el-row class="mb-4">
    <el-button>Default</el-button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </el-row>

  <br>

  <!-- Table表格 -->
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address" />
  </el-table>

  <br>

  <el-pagination
    v-model:current-page="currentPage4"
    v-model:page-size="pageSize4"
    :page-sizes="[100, 200, 300, 400]"
    layout="total, sizes, prev, pager, next, jumper"
    :total="400"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />
</template>

<style scoped>

</style>

打开浏览器,查看页面效果如下:

Pagination 分页组件的属性如下:

对于分页组件我们需要关注的是如下几个重要属性(可以通过查阅官网组件中最下面的组件属性详细说明得到):

  • background: 添加北京颜色,也就是上图蓝色背景色效果。
  • layout: 分页工具条的布局,其具体值包含 sizes, prev, pager, next, jumper, total 这些值
  • total: 数据的总数量

对于分页组件,除了上述几个属性,还有 2 个非常重要的事件我们需要去学习:

  • size-change : pageSize 改变时会触发
  • current-change :currentPage 改变时会触发

对话框组件

在保留当前页面状态的情况下,告知用户并承载相关操作。也就是一个弹窗.

首先我们需要在 ElementPlus 官方找到 Dialog 组件,如下图所示:

然后复制如下代码到我们的组件文件 Element.vue<template></template> 模块中:

<el-button @click="dialogTableVisible = true">
    打开对话框
  </el-button>

  <el-dialog v-model="dialogTableVisible" title="Shipping address">
    <el-table :data="tableData">
      <el-table-column property="date" label="Date" width="150" />
      <el-table-column property="name" label="Name" width="200" />
      <el-table-column property="address" label="Address" />
    </el-table>
  </el-dialog>

然后复制如下代码到我们的组件文件 Element.vue<script></script> 模块中:

const dialogTableVisible = ref(false)

最终,完成的 Element.vue 的代码如下:

<script setup>
import { ref } from 'vue'

const tableData = [
  {date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-02', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-04', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-01', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'}
]

const currentPage4 = ref(4)
const pageSize4 = ref(100)

const handleSizeChange = (val) => {
  console.log(`${val} items per page`)
}
const handleCurrentChange = (val) => {
  console.log(`current page: ${val}`)
}

// Dialog对话框
const dialogTableVisible = ref(false)
</script>

<template>

  <!-- Button按钮 -->
  <el-row class="mb-4">
    <el-button>Default</el-button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </el-row>

  <br>

  <!-- Table表格 -->
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address" />
  </el-table>

  <br>

  <el-pagination
    v-model:current-page="currentPage4"
    v-model:page-size="pageSize4"
    :page-sizes="[100, 200, 300, 400]"
    layout="total, sizes, prev, pager, next, jumper"
    :total="400"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />

  <br>

  <el-button @click="dialogTableVisible = true">
    打开对话框
  </el-button>

  <el-dialog v-model="dialogTableVisible" title="Shipping address">
    <el-table :data="tableData">
      <el-table-column property="date" label="Date" width="150" />
      <el-table-column property="name" label="Name" width="200" />
      <el-table-column property="address" label="Address" />
    </el-table>
  </el-dialog>

</template>

<style scoped>

</style>

打开浏览器,最终的页面效果如下:

[!TIP] Dialog 对话框组件使用的关键点,就是控制其显示与隐藏。 通过 v-model 给定的 boolean 值,来控制 Dialog 的显示与隐藏。

表单组件

Form 表单:由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据。

表单在我们前端的开发中使用的还是比较多的,接下来我们学习这个组件,与之前的流程一样,我们首先需要在 ElementPlus 的官方找到对应的组件示例:如下图所示:

然后复制如下代码到我们的组件文件 Element.vue<template></template> 模块中:

<!-- Form 表单 -->
  <el-form :inline="true" :model="formInline" class="demo-form-inline">//model表示绑定的数据模型.inline为true是表示下面所有的表单项都在同一行里显示.
    <el-form-item label="Approved by">
      <el-input v-model="formInline.user" placeholder="Approved by" clearable />
    </el-form-item>//这个就是一个正常的文本输入框.placeholder的位置是提示信息;clearable这个属性则会添加一个删除的按钮.

    <el-form-item label="Activity zone">
      <el-select v-model="formInline.region" placeholder="Activity zone" clearable>
        <el-option label="Zone one" value="shanghai" />
        <el-option label="Zone two" value="beijing" />//注意,value是提交的时候这个选项的值,而label是显示在下拉列表中的值.
      </el-select>
    </el-form-item>//这就是两个下拉列表.

    <el-form-item label="Activity time">
      <el-date-picker v-model="formInline.date" type="date" placeholder="Pick a date" clearable/>
    </el-form-item>//选择时间.注意看下后面的完整代码这部分的注释.

    <el-form-item>
      <el-button type="primary" @click="onSubmit">Query</el-button>
    </el-form-item>
  </el-form>

然后复制如下代码到我们的组件文件 Element.vue<script></script> 模块中:

// Form表单
const formInline = ref({
  user: '',
  region: '',
  date: '',
})//这里也可以命名成user

const onSubmit = () => {
  console.log('submit!')
}

最终,完成的 Element.vue 的代码如下:

<script setup>
import { ref } from 'vue'

const tableData = [
  {date: '2016-05-03', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-02', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-04', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'},
  {date: '2016-05-01', name: 'Tom', address: 'No. 189, Grove St, Los Angeles'}
]

const currentPage4 = ref(4)
const pageSize4 = ref(100)

const handleSizeChange = (val) => {
  console.log(`${val} items per page`)
}
const handleCurrentChange = (val) => {
  console.log(`current page: ${val}`)
}

// Dialog对话框
const dialogTableVisible = ref(false)

// Form表单
const formInline = ref({
  user: '',
  region: '',
  date: '',
})

const onSubmit = () => {
  console.log('submit!')
}
</script>

<template>

  <!-- Button按钮 -->
  <el-row class="mb-4">
    <el-button>Default</el-button>
    <el-button type="primary">Primary</el-button>
    <el-button type="success">Success</el-button>
    <el-button type="info">Info</el-button>
    <el-button type="warning">Warning</el-button>
    <el-button type="danger">Danger</el-button>
  </el-row>

  <br>

  <!-- Table表格 -->
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column prop="date" label="Date" width="180" />
    <el-table-column prop="name" label="Name" width="180" />
    <el-table-column prop="address" label="Address" />
  </el-table>

  <br>

  <el-pagination
    v-model:current-page="currentPage4"
    v-model:page-size="pageSize4"
    :page-sizes="[100, 200, 300, 400]"
    layout="total, sizes, prev, pager, next, jumper"
    :total="400"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
  />

  <br>

  <el-button @click="dialogTableVisible = true">
    打开对话框
  </el-button>

  <el-dialog v-model="dialogTableVisible" title="Shipping address">
    <el-table :data="tableData">
      <el-table-column property="date" label="Date" width="150" />
      <el-table-column property="name" label="Name" width="200" />
      <el-table-column property="address" label="Address" />
    </el-table>
  </el-dialog>

  <br><br>

  <!-- Form 表单 -->
  <el-form :inline="true" :model="formInline" class="demo-form-inline">
    <el-form-item label="Approved by">
      <el-input v-model="formInline.user" placeholder="Approved by" clearable />
    </el-form-item>

    <el-form-item label="Activity zone">
      <el-select v-model="formInline.region" placeholder="Activity zone" clearable>
        <el-option label="Zone one" value="shanghai" />
        <el-option label="Zone two" value="beijing" />
      </el-select>
    </el-form-item>

    <el-form-item label="Activity time">
      <el-date-picker v-model="formInline.date" type="date" placeholder="Pick a date" value-format="YYYY-MM-DD" clearable/>//value-format表示绑定时的数据格式,也就是提交时的数据格式.另外,注意这里的格式全部都是大小的YYYYMMDD,这些和java的不太一样
    </el-form-item>

    <el-form-item>
      <el-button type="primary" @click="onSubmit">Query</el-button>
    </el-form-item>
  </el-form>

</template>

<style scoped>

</style>

打开浏览器,查看页面效果:

案例

需求:基于 ElementPlus 组件库制作如下页面,并异步获取数据,完成页面展示。

1). 准备工作

由于在案例中,我们需要在 vue 项目中使用 Axios,需要安装 axios,需要在当前项目的目录下执行如下命令:

npm install axios

2). 编码实现

views 目录下,再定义一个文件 EmpList.vue,具体代码实现如下:

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'

const searchEmp = ref({
  name: '',
  gender: '',
  job: '',
})

onMounted(() => {
  search();
})

const search = async () => {
  const url = `https://web-server.itheima.net/emps/list?name=${searchEmp.value.name}&gender=${searchEmp.value.gender}&job=${searchEmp.value.job}`
  const result = await axios.get(url)
  tableData.value = result.data.data
}

const clear = () => {
  searchEmp.value = { name: '', gender: '', job: '' }
  search();
}

let tableData = ref([])
</script>

<template>
  <div id="center">
      <!-- 搜索表单 -->
    <el-form :inline="true" :model="searchEmp" class="demo-form-inline">
      <el-form-item label="姓名">
        <el-input v-model="searchEmp.name" placeholder="请输入姓名" clearable />
      </el-form-item>
      <el-form-item label="性别">
        <el-select v-model="searchEmp.gender" placeholder="请选择" clearable>
          <el-option label="男" value="1" />
          <el-option label="女" value="2" />
        </el-select>
      </el-form-item>
      <el-form-item label="职位">
        <el-select v-model="searchEmp.job" placeholder="请选择" clearable>
          <el-option label="班主任" value="1" />
          <el-option label="讲师" value="2" />
          <el-option label="咨询师" value="3" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="search">查询</el-button>
        <el-button type="primary" @click="clear">清空</el-button>
      </el-form-item>
    </el-form>
    <br>

    <!-- 表格 -->
    <el-table :data="tableData" border style="width: 100%; ">//width表示占用父元素的100%的宽度
      <el-table-column prop="id" label="ID" width="80" align="center" />
      <el-table-column prop="name" label="姓名" width="100" align="center" />
      <el-table-column label="头像" width="120" align="center">//上面这个prop属性没有用了,因为我们已经自定义下面的内容了.
        <template #default="scope">//default就是我们自定义列的内容
          <img :src="scope.row.image" width="50">//表示这一行数据的image字段的值.注意我们这里需要动态的绑定内容.高度和宽度是等比例缩放的,因此,设置一个就行了.
        </template>//这是自定义展示内容的方法,
      </el-table-column>
      <el-table-column prop="gender" label="性别" width="120" align="center">
        <template #default="scope">
          {{ scope.row.gender == 1 ? '男' : '女' }}
        </template>
      </el-table-column>
      <el-table-column label="职位" width="180" align="center">
        <template #default="scope">
          <span v-if="scope.row.job == 1">班主任</span>
          <span v-else-if="scope.row.job == 2">讲师</span>
          <span v-else-if="scope.row.job == 3">咨询师</span>
          <span v-else>其他</span>
        </template>
      </el-table-column>
      <el-table-column prop="entrydate" label="入职日期" width="180" align="center" />
      <el-table-column prop="updatetime" label="更新时间" align="center" />//align表示单元格里的数据居中显示
    </el-table>
  </div>
</template>

<style scoped>
#center {
  width: 70%;
  margin: auto;
  margin-top: 100px;
}
</style>

App.vue 中引入 EmpList.vue 文件

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

<template>
  <EmpList></EmpList>
</template>

<style scoped>

</style>

3). 打开浏览器,查看页面效果