Day15 Web前端实战:Vue工程化、ElementPlus
目录
- Vue工程化
- ElementPlus
Web开发

什么是Vue
- Vue 是一款用于构建用户界面的渐进式的JavaScript框架。 (官方:https://cn.vuejs.org/)。

1. Vue工程化
小白眼中的前端开发

工程化
- 模块化:项目划分若干模块,单独开发、维护,提高效率
- 组件化:将页面的各个组成部分封装为一个一个的组件,提高复用
- 规范化:提供标准统一的目录结构、编码规范、开发流程
- 自动化:项目的构建、开发、测试、打包、部署
- 工程化:(模块化、组件化、规范化、自动化)在企业级的前端项目开发中,把前端开发所需的工具、技术、流程、经验等进行规范化、 标准化。(统一规范、提高复用、便于维护)

1.1 环境准备
- 介绍:create-vue是Vue官方提供的最新的脚手架工具,用于快速生成一个工程化的Vue项目。
create-vue提供了如下功能:
- 统一的目录结构
- 本地调试
- 热部署
- 单元测试
- 集成打包上线
- 依赖环境NodeJS:Node.js®是一个免费、开源、跨平台的JavaScript运行时环境,它让开发人员能够创建服务器、Web应用、命令行工具和脚本。

安装NodeJS:安装在develop下,如D:\develop\nodejs
npm:Node Package Manager,是NodeJS的软件包管理器。

图6 npm
node -v
npm -v
配置npm的全局安装路径、切换为淘宝镜像,加速下载
npm config set prefix "D:\develop\nodejs"
npm config set registry https://registry.npmmirror.com

1.2 Vue项目简介
Vue项目-创建
- 创建一个工程化的Vue项目,执行命令:npm create vue@3.3.4
- 提示:执行上述指令,将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具
Vue项目-安装依赖
- 进入项目目录,执行命令安装当前项目的依赖:npm install
- 注意:创建项目以及安装依赖的过程,都是需要联网的。
# 项目工作目录 如G:\workspace\duSSM\vue
npm create vue@3.3.4
# 输入项目名 vue-project1
cd vue-project1
npm install
npm run dev

Vue项目-项目结构
使用VS Code打开Vue项目。

Vue项目-启动


小结
- Vue项目操作
- 创建:npm create vue@版本号
- 安装依赖:npm install
- 启动:npm run dev

③ Vue项目执行流程
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App 张婧怡</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
src\main.js
import { createApp } from 'vue';
import App from './App.vue'
//import './assets/main.css'
createApp(App).mount('#app')
src\App.vue
<!--定义JS,控制模板部分的数据和行为(JS)-->
<script setup>
import { ref } from 'vue'
//声明一个响应式数据message
const message = ref('Hello Vue3 张婧怡');
</script>
<!--模板部分,控制的是页面的结构(HTML)-->
<template>
<h1>{{ message }}</h1>
</template>
<!--当前组件的css样式-->
<style scoped>
</style>



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

- 选项式API:可以用包含多个选项的对象来描述组件的逻辑,如:data,methods,mounted等。选项定义的属性都会暴露在函数内部的this上,它会指向当前的组件实例。
组合式API:是Vue3提供的一种基于函数的组件编写方式,通过使用函数来组织和复用组件的逻辑。它提供了一种更灵活、更可组合的方式来编写组件。
当你不需要使用构建工具,或者打算主要在低复杂度的场景中使用Vue,例如渐进增强的应用场景,推荐采用选项式API。
- 当你打算用Vue构建完整的单页应用,推荐采用组合式API+单文件组件。
src\views\ApiDemo.vue
<script setup>
//引入ref函数
import { ref,onMounted } from'vue';
//声明响应式数据
const count = ref(0);
//声明函数-在组合式API中没有this
function increment(){
count.value++;
}
//钩子函数
onMounted(()=> {
console.log('Vue mounted..');
})
</script>
<template>
<button @click="increment">点击我(张婧怡) 计数:{{ count }}</button>
</template>
<style scoped>
button{
background-color: #4CAF50;
color: white;
padding: 14px 20px;
margin: 8px 0;
border: none;
cursor: pointer;
width: 50;
}
</style>
src\App.vue
<!--定义JS,控制模板部分的数据和行为(JS)-->
<script setup>
import ApiDemo from'./views/ApiDemo.vue'
</script>
<!--模板部分,控制的是页面的结构(HTML)-->
<template>
<ApiDemo></ApiDemo>
</template>
<!--当前组件的css样式-->
<style scoped>
</style>


- setup:是一个标识,告诉Vue需要进行一些处理,让我们可以更简洁的使用组合式API。
- ref():接收一个内部值,返回一个响应式的ref对象,此对象只有一个指向内部值的属性 value。
- 注意:在Vue中的组合式API使用时,是没有this对象的,this对象是undefined。
⑤ 案例
在Vue项目中基于组合式API完成用户列表数据渲染
- 要求在页面加载完毕之后,发送异步请求,加载数据,渲染表格。
- 项目中用到axios,就需要安装axios的依赖:
npm install axios
src\views\EmpList.vue
<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';
//声明响应式数据
const name = ref('');
const gender = ref('');
const job = ref('');
const userList = ref([]);
//声明函数 -箭头函数 - await&async
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.value = result.data.data;
}
//钩子函数
onMounted(()=>{
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-if="user.job == 1">班主任</span>
<span v-else-if="user.job == 2">讲师</span>
<span v-else-if="user.job == 3">学工主管</span>
<span v-else-if="user.job == 4">教研主管</span>
<span v-else-if="user.job == 5">咨询师</span>
<span v-else>其他</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>
src\App.vue
<!--定义JS,控制模板部分的数据和行为(JS)-->
<script setup>
import ApiDemo from'./views/ApiDemo.vue'
import EmpList from'./views/EmpList.vue'
</script>
<!--模板部分,控制的是页面的结构(HTML)-->
<template>
<ApiDemo></ApiDemo>
<EmpList></EmpList>
</template>
<!--当前组件的css样式-->
<style scoped>
</style>

小结
在组合式API中有没有this ? 在组合式API中如何更新响应式数据内容 ?

2. ElementPlus
什么是ElementPlus
- Element:是饿了么团队研发的,基于 Vue3,面向设计师和开发者的组件库。
- 组件:组成网页的部件,例如 超链接、按钮、图片、表格、表单、分页条等等。
- 官网:https://element-plus.org/zh-CN/#/zh-CN

目录
- 快速入门
- 常见组件
- 案例
① 快速入门
Element Plus快速入门
- 准备工作:
- 创建vue项目
- 参照官方文档,安装Element Plus组件库(在当前工程的目录下):
npm install element-plus@2.4.4 --save - main.js中引入Element Plus组件库(参照官方文档)
//引入ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).use(ElementPlus).mount('#app')
- 制作组件:访问Element官方文档,复制组件代码,调整
# 项目工作目录 如G:\workspace\duSSM\vue
npm create vue@3.3.4
# 输入项目名 vue-project2
cd vue-project2
npm install
npm install element-plus@2.4.4 --save
npm run dev

index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Element Plus快速入门(张婧怡)</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
src\main.js
import { createApp } from 'vue'
//引入ElementPlus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
createApp(App).use(ElementPlus).mount('#app')
src\App.vue
<script setup>
import ElementDemo from './views/ElementDemo.vue'
</script>
<template>
<h1>Element Demo(张婧怡)</h1>
<hr />
<ElementDemo />
</template>
<style scoped>
</style>
src\views\ElementDemo.vue
<script setup>
import {
Check,
Delete,
Edit,
Message,
Search,
Star,
} from '@element-plus/icons-vue'
</script>
<template>
<div class="button-row">
<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>
</div>
<div class="button-row">
<el-button plain>Plain</el-button>
<el-button type="primary" plain>Primary</el-button>
<el-button type="success" plain>Success</el-button>
<el-button type="info" plain>Info</el-button>
<el-button type="warning" plain>Warning</el-button>
<el-button type="danger" plain>Danger</el-button>
</div>
<div class="button-row">
<el-button :icon="Search" circle />
<el-button type="primary" :icon="Edit" circle />
<el-button type="success" :icon="Check" circle />
<el-button type="info" :icon="Message" circle />
<el-button type="warning" :icon="Star" circle />
<el-button type="danger" :icon="Delete" circle />
</div>
</template>
<style scoped>
.button-row{
margin-bottom:10px;
}
</style>

小结
ElementPlus的使用步骤
- 安装:npm install element-plus@2.4.4 –save
- 引入:在main.js中引入Element Plus(参照官方文档)
- 组件:访问官方文档中的组件,调整成我们需要的样子即可

② 常见组件
- 表格组件
- 分页条组件
- 对话框组件
- 表单组件
表格组件
用于展示多条结构类似的数据, 可对数据进行排序、筛选、对比或其他自定义操作。
src\views\ElementDemo.vue 相应位置添加如下代码
<div class="button-row">
<el-table :data="tableData" border style="width: 40%">
<el-table-column prop="date" label="生日" width="180" align="center" />
<el-table-column prop="name" label="姓名" width="180" align="center" />
<el-table-column prop="address" label="住址" header-align="center" />
</el-table>
</div>
<script>
const tableData = [
{ date: '2016-05-03', name: '张婧怡1', address: '南内环西街1号' },
{ date: '2016-05-02', name: '张婧怡2', address: '高校新区文华街125号' },
{ date: '2016-05-04', name: '张婧怡3', address: '南内环西街1号' },
{ date: '2016-05-01', name: '张婧怡4', address: '南内环西街1号' }]
</script>

小结

分页条组件
- 当数据量过多时,使用分页操作分解数据。
- 默认Element Plus的组件是英文的,如果希望使用中文语言,可以做如下配置:
//引入中文语言
import zhCn from 'element-plus/es/locale/lang/zh-cn'
createApp(App).use(ElementPlus, { locale: zhCn }).mount('#app')
src\main.js 修改如下
import { createApp } from 'vue';
//引入ElementPlus
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css';
import zhCn from 'element-plus/es/locale/lang/zh-cn';
import App from './App.vue';
createApp(App).use(ElementPlus, { locale: zhCn }).mount('#app')
src\views\ElementDemo.vue 相应位置添加如下代码
<script setup>
mport { ref } from 'vue';
const currentPage=ref(1);//当前页码
const pagesize=ref(10);//每页展示记录数
const total=ref(400);//总记录数
const background=ref(true);//是否有背景色
const handlesizeChange = (val)=> {
console.log(`每页展示:${val}条`);
}
const handleCurrentchange= (val)=> {
console.log(`当前页码是:${val}`);
}
</script>
<div class="button-row">
<el-pagination
:current-page="currentPage"
:page-sizes="[10, 20, 30, 45]"
:page-size="pagesize"
:Background="background"
class="pagination"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handlesizeChange"
@current-change="handleCurrentchange"
/>
</div>


对话框组件
在保留当前页面状态的情况下,告知用户并承载相关操作。
src\views\ElementDemo.vue 相应位置添加如下代码
<script>
const dialogTableVisible = ref(false);
</script>
<div class="button-row">
<el-button class="!ml-0" plain @click="dialogTableVisible = true">打开Dialog对话框</el-button>
<el-dialog v-model="dialogTableVisible" title="收货地址" width="500">
<el-table :data="tableData">
<el-table-column property="date" label="日期" width="120" />
<el-table-column property="name" label="姓名" width="100" />
<el-table-column property="address" label="收货地址" />
</el-table>
</el-dialog>
</div>


表单组件
表单包含 输入框, 单选框, 下拉选择, 多选框 等用户输入的组件。 使用表单,可以收集、验证和提交数据。
src\views\ElementDemo.vue 相应位置添加如下代码
<script>
//表单
const user = ref({
username: '',
gender: '',
hiredate: '',
})
const onSubmit = () => {
console.log(user.value)
}
</script>
<div class="button-row">
<el-form :inline="true" :model="user" class="demo-form-inline">
<el-form-item label="用户名">
<el-input v-model="user.username" placeholder="请输入用户名" clearable />
</el-form-item>
<el-form-item label="性别">
<el-select
v-model="user.gender"
placeholder="请选择性别">
<el-option label="男" value="1" />
<el-option label="女" value="0" />
</el-select>
</el-form-item>
<el-form-item label="入职日期">
<el-date-picker
v-model="user.hiredate"
type="date"
placeholder="请选择"
value-format="YYYY-MM-DD"
clearable
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交</el-button>
</el-form-item>
</el-form>
</div>


③ 案例
制作如下页面,并异步获取数据完成页面展示
页面布局
动态加载数据并渲染展示

src\App.vue 修改如下
<script setup>
// import ElementDemo from './views/ElementDemo.vue'
import EmpList from './views/EmpList.vue'
</script>
<template>
<!-- <h1>Element Demo(张婧怡)</h1> -->
<h1 style="text-align: center; width: 70%;margin: 0 auto;">员工列表(张婧怡)</h1>
<hr style="text-align: center; width: 70%;"/>
<EmpList />
</template>
<style scoped>
</style>
src\views\EmpList.vue
<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios'
//表单
const emp = ref({name: '', gender: '', job: '' })
const empList = ref([]);
const sertch = async () => {
const res = await axios.get('https://web-server.itheima.net/emps/list', { params: emp.value})
empList.value = res.data.data
}
const clear = () => {
emp.value = {name: '', gender: '', job: '' }
sertch()
}
onMounted(() => {
sertch()
})
// 时间格式化
const formatDateTime = (row, column) => {
const date = row[column.property];
if (!date) return '';
// 将T替换为空格
return date.replace('T', ' ');
}
</script>
<template>
<div id="container">
<el-form :inline="true" :model="emp" class="demo-form-inline">
<el-form-item label="姓名">
<el-input v-model="emp.name" placeholder="请输入姓名" clearable />
</el-form-item>
<el-form-item label="性别">
<el-select
v-model="emp.gender"
placeholder="请选择性别">
<el-option label="男" value="1" />
<el-option label="女" value="2" />
</el-select>
</el-form-item>
<el-form-item label="职位">
<el-select
v-model="emp.job"
placeholder="请选择">
<el-option label="班主任" value="1" />
<el-option label="讲师" value="2" />
<el-option label="学工主管" value="3" />
<el-option label="教研主管" value="4" />
<el-option label="咨询师" value="5" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="sertch">查询</el-button>
<el-button type="info" @click="clear">清空</el-button>
</el-form-item>
</el-form>
<el-table :data="empList" border style="width: 100%">
<el-table-column prop="id" label="ID" width="100" align="center" />
<el-table-column prop="name" label="姓名" width="120" align="center" />
<el-table-column prop="address" label="头像" align="center" width="80">
<template #default="scope">
<el-avatar :src="scope.row.image" size="medium" />
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" width="80" align="center" >
<template #default="scope">
{{scope.row.gender == 1 ? '男' : '女'}}
</template>
</el-table-column>
<el-table-column prop="job" label="职位" width="120" 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-if="scope.row.job == 4">教研主管</span>
<span v-else-if="scope.row.job == 5">咨询师</span>
<span v-else>其他</span>
</template>
</el-table-column>
<el-table-column prop="entrydate" label="入职日期" align="center" width="180" />
<el-table-column prop="updatetime" label="更新时间" align="center" :formatter="formatDateTime" />
</el-table>
</div>
</template>
<style scoped>
#container{
width: 70%;
margin: 0 auto;
}
</style>
