今天开始使用 vue3 + ts 搭建一个项目管理的后台,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关注本专栏,学习更多前端vue知识,然后开篇先简单介绍一下本项目用到的技术栈都有哪几个方面(阅读本文章能够学习到的技术):
vite:快速轻量且功能丰富的前端构建工具,帮助开发人员更高效构建现代Web应用程序。
pnpm:高性能、轻量级npm替代品,帮助开发人员更加高效地处理应用程序的依赖关系。
Vue3:Vue.js最新版本的用于构建用户界面的渐进式JavaScript框架。
TypeScript:JavaScript的超集,提供了静态类型检查,使得代码更加健壮。
Animate:基于JavaScript的动画框架,它使开发者可以轻松创建各种炫酷的动画效果。
vue-router:Vue.js官方提供的路由管理器与Vue.js紧密耦合,非常方便与Vue.js一同使用。
Pinia:Vue3构建的Vuex替代品,具有响应式能力,提供非常简单的 API,进行状态管理。
element-plus:基于Vue.js 3.0的UI组件库,用于构建高品质的响应式Web应用程序。
axios:基于Promise的HTTP客户端,可以在浏览器和node.js中使用。
three:基于JavaScript的WebGL库,开发者可以编写高性能、高质量的3D场景呈现效果。
echarts:基于JavaScript的可视化图表库,支持多种类型的图表,可根据需要自行安装。
当然还有许多其他的需要安装的第三方库,这里就不再一一介绍了,在项目中用到的地方自行会进行讲解,大家自行学习即可,现在就让我们走进vue3+ts的实战项目吧。
目录
品牌管理模块静态搭建
品牌管理数据展示
分页器点击相关操作
对话框静态搭建
实现添加修改删除业务的功能
表单自定义规则校验
品牌管理模块静态搭建
品牌管理模块的静态搭建这里需要使用element-plus组件库提供的相关标签实现快速搭建样式,我们采用卡片样式,最外层用el-card进行包裹:
<template>
<el-card class="box-card">
</el-card>
</template>
卡片里面的样式就可以根据自己的喜好随意搭配了,这里我存放了一个按钮、表格和分页器:
<el-card class="box-card">
<!-- 卡片顶部添加按钮 -->
<el-button type="primary" size="default" icon="Plus">添加品牌</el-button>
<!-- 表格组件,用于展示已有的平台数据 -->
<el-table style="margin: 10px 0px" border>
<el-table-column
label="序号"
width="80px"
align="center"
></el-table-column>
<el-table-column label="品牌名称"></el-table-column>
<el-table-column label="品牌Logo"></el-table-column>
<el-table-column label="品牌操作"></el-table-column>
</el-table>
<!-- 分页器组件 -->
<el-pagination
v-model:current-page="pageNo"
v-model:page-size="limit"
:page-sizes="[3, 5, 7, 9]"
background="true"
layout="prev, pager, next, jumper, ->, sizes, total"
:total="400"
/>
</el-card>
通过JS定义相关变量实现响应式数据:
<script setup lang="ts">
import { ref } from 'vue'
// 当前的页码
let pageNo = ref<number>(1)
// 每页展示多少条数据
let limit = ref<number>(3)
</script>
最后实现的静态页面效果如下所示:
品牌管理数据展示
在显示内容方面,我们可用借助Table组件库中的prop属性进行展示内容
对应的数据就会展示出来:
使用prop默认是以div包裹进行展示的,当然这里也可以使用template插槽进行展示数据,接下来的图片和操作都可以使用插槽来完成:
分页器点击相关操作
接下来开始对点击分页器进行相关数据切换操作,这里我们采用的是组件库中的分页器给我们提供的相关API进行操作:
我们在点击分页按钮后,其API会自动将相关的页数进行一个注入,所以我们不需要进行传递参数来实现:
因为是自动注入相关的页码值数据,所以我们也可以直接调用获取数据的方法,不需要再额外定义一个新的函数,定义分页数也可以采用相同的方法,不过为了让在点击分页数之后,页码值会跳转到第一页,可以传递一个默认参数,如果没有传递参数的话,默认就是1,传递的话就会覆盖默认值:
对话框静态搭建
在项目中添加品牌和修改品牌的相关数据都需要借助对话框来实现,所以这里就需要简单的搭建一下对话框并使用,如下借助组件库使用:
<!-- 对话框组件:在添加品牌和修改已有品牌的业务时侯使用该结构 -->
<el-dialog v-model="dialogFormVisible" title="添加品牌">
<el-form style="width: 80%">
<el-form-item label="品牌名称" label-width="80px">
<el-input placeholder="请您输入品牌名称"></el-input>
</el-form-item>
<el-form-item label="品牌LOGO" label-width="80px">
<el-upload
class="avatar-uploader"
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
</el-form>
<!-- 具名插槽:设置相关按钮 -->
<template #footer>
<el-button type="primary" size="default" @click="cancel">
取消
</el-button>
<el-button type="primary" size="default" @click="confirm">
确定
</el-button>
</template>
</el-dialog>
当然我们要为添加品牌和修改品牌的按钮设置点击事件来更改
// 添加品牌按钮的回调
const addTrademark = () => {
// 对话框显示
dialogFormVisible.value = true
}
// 修改已有品牌数据的回调
const updateTrademark = () => {
// 对话框显示
dialogFormVisible.value = true
}
// 对话框底部取消按钮
const cancel = () => {
// 对话框隐藏
dialogFormVisible.value = false
}
// 对话框底部确定按钮
const confirm = () => {
// 对话框隐藏
dialogFormVisible.value = false
}
最后呈现的结果如下:
接下来给上传图片设置相关的格式校验:
// 上传图片组件,钩子是在图片上传成功之前触发,上传文件之前可以约束文件类型与大小
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
if (
rawFile.type == 'image/png' ||
rawFile.type == 'image/jpg' ||
rawFile.type == 'image/gif' ||
rawFile.type == 'image/jpeg'
) {
if (rawFile.size / 1024 / 1024 < 4) {
return true
} else {
ElMessage({
type: 'error',
message: '上传文件大小应小于4M',
})
}
} else {
ElMessage({
type: 'error',
message: '上传文件格式务必PNG|JPG|GIF|JPEG',
})
return false
}
}
// 图片上传成功的钩子
const handleAvatarSuccess: UploadProps['onSuccess'] = (response) => {
// 收集图片的地址
trademarkParams.logoUrl = response.data
}
实现添加修改删除业务的功能
接下来实现数据的增删改操作,当然这里的话也是要和后端搭配借助相关的接口实现,如下:
// 书写品牌管理模块的接口
import request from '@/utils/request'
// 引入ts类型
import type { TradeMarkResponseData, TradeMark } from './type'
// 品牌管理模块接口地址
enum API {
// 获取已有品牌接口
TRADEMAKE_URL = '/admin/product/baseTrademark/',
// 添加品牌
ADDTRADEMAKE_URL = '/admin/product/baseTrademark/save',
// 修改品牌
UPDATETRADEMAKE_URL = '/admin/product/baseTrademark/update',
// 删除已有品牌数据
DELETE_URL = '/admin/product/baseTrademark/remove/',
}
// 获取已有品牌的接口方法:page:获取第几页;limit:获取几个已有品牌的数据
export const reqHasTrademark = (page: number, limit: number) =>
request.get<any, TradeMarkResponseData>(API.TRADEMAKE_URL + `${page}/${limit}`)
// 添加和修改已有品牌接口方法
export const reqAddOrUpdateTrademark = (data: TradeMark) => {
// 修改已有品牌的数据
if (data.id) {
return request.put<any, any>(API.UPDATETRADEMAKE_URL, data)
} else {
// 新增品牌数据
return request.post<any, any>(API.ADDTRADEMAKE_URL, data)
}
}
// 删除某一个已有品牌的数据
export const reqDeleteTrademark = (id: number) => request.delete<any, any>(API.DELETE_URL + id)
在点击对话框的确定按钮后调用添加数据业务,因为添加数据是不需要id的,后端会自动帮助我们生成相应的id,但是修改业务需要借助相应id,所以这里我们通过id的与否来判断是我们是选择添加品牌还是修改品牌:
// 对话框底部确定按钮
const confirm = async () => {
let result: any = await reqAddOrUpdateTrademark(trademarkParams)
// 添加品牌成功
if (result.code == 200) {
// 对话框隐藏
dialogFormVisible.value = false
// 弹出提示信息
ElMessage({
type: 'success',
message: trademarkParams.id ? '修改品牌成功' : '添加品牌成功',
})
// 再次发请求获取已有全部的品牌数据
hasTrademark(trademarkParams.id ? pageNo.value : 1)
} else {
// 添加品牌失败
ElMessage({
type: 'error',
message: trademarkParams.id ? '修改品牌失败' : '添加品牌失败',
})
}
}
当我们点击修改按钮后,通过点击事件会自动获取当前修改品牌的相关数据,因为修改数据是具有其ID的,所以这里我们通过ES6语法对trademarkParams进行一个合并:
// 修改已有品牌数据的回调
const updateTrademark = (row: TradeMark) => {
// 对话框显示
dialogFormVisible.value = true
// // 展示已有品牌的数据
// trademarkParams.id = row.id
// trademarkParams.tmName = row.tmName
// trademarkParams.logoUrl = row.logoUrl
// 使用ES6合并语法
Object.assign(trademarkParams, row)
}
删除数据的方式同样简单,这里借助组件库中的气泡提示框进行书写,通过相关事件confirm来对其数据进行一个删除:
// 删除按钮的回调
const removeTradeMark = async (id: number) => {
// 点击确定按钮删除已有品牌请求
let result = await reqDeleteTrademark(id)
if (result.code == 200) {
ElMessage({
type: 'success',
message: '删除品牌成功',
})
// 再次发请求获取已有全部的品牌数据
hasTrademark(trademarkArr.value.length > 1 ? pageNo.value : pageNo.value - 1)
} else {
ElMessage({
type: 'error',
message: '删除品牌失败',
})
}
}
呈现的结果如下:
表单自定义规则校验
接下来仍然需要对对话框中的文字和图片区域进行相关校验,校验规则如下:
// 品牌自定义校验规则(文字)
const validatorTmName = (_rule: any, value: any, callback: any) => {
if (value.trim().length >= 2) {
callback()
} else {
// 校验未通过返回的错误信息
callback(new Error('品牌名称位数必须大于等于俩位'))
}
}
// 品牌自定义校验规则(图片)
const validatorLogoUrl = (_rule: any, value: any, callback: any) => {
// 如果图片上传
if (value) {
callback()
} else {
callback(new Error('LOGO图片务必上传!'))
}
}
// 设置表单校验规则对象
const rules = {
tmName: [{ required: true, trigger: 'blur', validator: validatorTmName }],
logoUrl: [{ required: true, trigger: 'change', validator: validatorLogoUrl }],
}
设置完校验规则之后,我们需要在点击按钮之后对整个表单进行校验,如果校验不通过需要提示,当然这里需要通过ref来获取form表单的数据进行验证:
验证完成之后,在点击确定或者重新打开表单时需要清除相关的表单验证规则,因为初始进行是没有进行表单验证的,所以我们要使用可选链操作符进行判断:
最终达到的效果如下:
本项目的品牌管理页面功能的搭建就讲解到这,下一篇文章将继续讲解其它模块的主体内容,关注博主学习更多前端vue知识,您的支持就是博主创作的最大动力!