elementplus官网:一个 Vue 3 UI 框架 | Element Plus (element-plus.org)
npm install element-plus --save
查看package.json中存在依赖表示成功安装
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
注意:vue3不支持elementUI,所以选择以下搭配其中之一(这里我选的是2)
(1)vue2+elementUI
(2)vue3+elementPlus
点击官网上方菜单栏的组件,点击
点击布局容器可以看到示例,我们选择使用最下面的侧边栏的示例代码
Container 布局容器 | Element Plus (element-plus.org)
查看示例的代码,这里选择手动引入(elementplus还支持自动按需引入)
代码主要分成四部分,第一部分我们需要放在template里面,第二部分是选择按需部分引入的方式,我们可以不管,第三部分是放在script里的data部分里面也就是提供页面的数据,具体填入形式如下
第四部分是页面的样式,不重要,我们可以不使用
引入完成功编译运行后的结果:
//global.css
html,body,div{
margin: 0;
padding: 0;
}
html,body{
height: 100%;
}
然后再main.js里引入 (不要忘了加 ./ )
将所有菜单的高度改成100% 这个时候滚动页面整个页面不会跟随滚动,菜单栏可以单独滚动
自行调整样式后:
效果:
先安装elementPlus图标:
npm install --save @element-plus/icons
到elementPlus官网图标下赋值图标标签代码
Icon 图标 | Element Plus (element-plus.org)
Tom
效果:
编写收缩的方法
methods: {
collapse(){ //点击收缩按钮触发
this.isCollapse=!this.isCollapse
}
}
此时收缩会出现问题,文字没有隐藏,宽度不对
所以需要将宽度设为动态的
然后再将导航的名称都放在span标签里,就会自动收缩进去
然后更改如果收缩了,图标就改变,这里我用v-if和v-else的组合
再结合前面设置的isCollapse状态
使得图标可以切换
效果:
后台管理系统
效果:
linehight如果设置和垂直高度一致,就会居中,否则就会在上方或者下面
style="line-height: 60px"
效果:
首先去掉e-menu的边框的颜色
border-right-color: transparent
再在e-side里面添加阴影属性
box-shadow: 2px 0 6px rgb(0 21 41 / 35%)
效果:
进到官网页面,pagination
Pagination 分页 | Element Plus (element-plus.org)
copy“完整功能”代码
黏贴在e-mian标签下的e-table下
此时可以看到底部的效果,并且还没有生效
搜索
效果:
扩展多个输入框:
效果:
增删导入导出
新增
批量删除
导入
导出
表格里的编辑、删除
slot-scope="scope"
编辑
删除
最后的效果:
(108条消息) vue项目中table表格固定表头和首尾列_梨城毒妃的博客-CSDN博客_vue固定表头
至此管理系统的前端雏形已经产生
在官网的面包屑模块下:
Breadcrumb 面包屑 | Element Plus (element-plus.org)
主页
用户管理
promotion list
promotion detail
效果:
1、创建项目,引入lombok,mybatisplus,mysql等等依赖
后两个依赖在项目勾选时候可以自动导入,所以只用关注前面的
org.projectlombok
lombok
provided
com.baomidou
mybatis-plus-boot-starter
3.4.1
com.alibaba
druid
1.1.16
com.mysql
mysql-connector-j
runtime
8.0.31
com.baomidou
mybatis-plus-core
3.4.3.1
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
2、编写yml文件
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
username: root
password: 123456
main:
banner-mode: off
mybatis-plus:
global-config:
banner: false
server:
port: 8081
效果:
项目结构:
测试springboot
建立表:sys_user
写入数据:
建立包和实体接口
使接口继承BaseMapper,并注解为Mapper
在写任何controller时候前面都要加一个注解:RestController
测试连接数据库
用lambdaquery来写查询
@RequestMapping("/select") //访问路径
public List select(){
LambdaQueryWrapper lqw = new LambdaQueryWrapper();
// lqw.like(User::getUsername,'a');
List userList = userDao.selectList(lqw);
return userList;
}
结果:
先设置拦截器:(一定要把pom里面的所有关于mybatisplus的依赖的版本号改成一致的)
编写接口:
后来发现要加total,所以改成返回Map
@GetMapping("/page")
public List fingPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize){
pageNum = (pageNum-1)*pageSize;
IPage page = new Page(pageNum,pageSize);
userDao.selectPage(page, null);
return page.getRecords();
}
用postman测试:(查出两条数据)
在vue页面查看要传输的数据:
编写传数据的方法:
created() {
//请求分页查询数据
fetch("http://localhost:9090/user/page?pageNum=1&pageSize=2").then(res => res.json()).then(
res =>{
console.log(res)
})
},
查看,出现了跨域问题 (前端端口与后端端口不一致)
选择在后端处理跨域
最简单方法:在controller类名前加@CrossOrigin注解,这是最简单的处理方式
比较完善的方法:加入如下代码
(94条消息) SpringBoot解决跨域问题_程序员青戈的博客-CSDN博客_springboot解决跨域问题 青戈
这个时候我们再次启动后台:此时控制台显示我们的数据获取成功
返回改成map后:(就分成了两组)
封装渲染时加载数据的代码为load
load(){
fetch("http://localhost:8081/page?pageNum="+this.pageNum+"&pageSize="+this.pageSize).then(res => res.json()).then(res => {
console.log(res)
this.tableData=res.data
this.total=res.total
})
}
在created函数内调用load
created() {
//请求分页查询数据
this.load()
}
created函数:在页面刷新时,重新加载数据,在vue3中有一个setup()注意里面不能用method里的方法也不能使用this
编写跟随页数更改跳转和重新渲染页面的两个方法:用于动态更改页码和显示数据数目
handleSizeChange(pageSize) handleCurrentChange
Pagination 分页 | Element Plus (element-plus.org)
handleSizeChange(pageSize){
this.pageSize = pageSize
this.load()
},
handleCurrentChange(pageNum){
this.pageNum=pageNum
this.load()
}
至此页码的所有功能都已激活
绑定搜索框,返回搜索数据
增加查询的名称username关键字
@GetMapping("/page")
public Map fingPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam String username){
pageNum = (pageNum-1)*pageSize;
Page page = new Page(pageNum,pageSize);
LambdaQueryWrapper lqw = new LambdaQueryWrapper();
lqw.like(User::getUsername,username);
userDao.selectPage(page, lqw);
Map hm = new HashMap<>();
hm.put("data",page.getRecords());
hm.put("total",page.getTotal());
return hm;
// return userService.findAll();
}
我们可以看到我们写完QuerWrapper后可以直接填写到selectPage函数第二个参数里(原来为null)非常巧妙
我们用postman输入参数尝试查询结果成功,注意此时我们并没有更改任何前端
我们成功后即可用v-model绑定前端的搜索框
然后写入data()(默认为空),然后在fetch函数里添加username字段
绑定前端搜索按钮事件为重新渲染数据
第一个搜索框的功能已经激活成功
扩展多条件查询(将其它两个搜索框也激活)
总结上面一个框激活的流程:
1、在接口里增加查询的参数,并且增加querymapper对象的方法
2、用v-model绑定搜索框数据,并且绑定按钮渲染函数
3、在后端data增加参数,并且增加fectch渲染函数的参数
清楚了流程,我们做起来就事半功倍了
至此多条件查询已激活所有搜索框
激活新增,批量删除,导入,导出四个按钮
驼峰映射是自动的,它会把下划线去掉并把下划线原来后面的字母大写
如:user_name->userName
用postman测试如果觉得复杂,可以用swaggerUI(一个接口测试文档)
(94条消息) SpringBoot集成swagger-ui以及swagger分组显示_程序员青戈的博客-CSDN博客_swagger ui 分组 第一步:
导入swagger依赖:
创建swaggerConfig类:
更改包的地址:
我觉得还是postman好用
使用axios代替fetch (fetch太繁琐)
(94条消息) Vue项目搭建常用的配置文件,request.js和vue.config.js_程序员青戈的博客-CSDN博客_vue config.headers配置
安装axios
npm i axios -s
新建utils文件夹,并新建js文件
黏贴封装的request.js代码:
import axios from 'axios'
const request = axios.create({
baseURL: '/api', // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!!
timeout: 5000
})
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
// config.headers['token'] = user.token; // 设置请求头
return config
}, error => {
return Promise.reject(error)
});
// response 拦截器
// 可以在接口响应后统一处理结果
request.interceptors.response.use(
response => {
let res = response.data;
// 如果是返回的文件
if (response.config.responseType === 'blob') {
return res
}
// 兼容服务端返回的字符串数据
if (typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
return res;
},
error => {
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default request
设置request为全局变量:
在vue2中用prototype设置,vue3中可以用app.config.globalProperties
来代替prototype
(94条消息) vue 3.0 prototype 替代用法_寻ing的博客-CSDN博客_vue3 prototype
我们使用axios后可以看到前后代码对比
使用前:
fetch("http://localhost:8081/page?pageNum="+this.pageNum+"&pageSize="+this.pageSize+"&username="+this.username
+"&email="+this.email+"&address="+this.address).then(res => res.json()).then(res => {
console.log(res)
this.tableData=res.data
this.total=res.total
})
使用后:
request.get("http://localhost:8081/page",{
params:{
pageNum:this.pageNum,
pageSize:this.pageSize,
username:this.username,
email:this.email,
address:this.address
}
}).then(res => {
console.log(res)
this.tableData= res.data
this.total = res.total
})
变得更加简洁,而且达到相同的功能效果
在查询后为了回复原来的页面,增加一个重置按钮
编写reset方法,思路就是把表单清空,并重新渲染页面,超级简单
reset(){
this.username=""
this.email=""
this.address=""
this.load()
}
dialog对话框编写:
在elementplus官网黏贴代码
Dialog 对话框 | Element Plus (element-plus.org)
This is a message
选择下面的嵌套表单的代码
open a Form nested Dialog
绑定新增按钮的事件handleAdd
编写确认按钮的事件save
在这之前要先把接口写好
这里写一个业务层的save接口,然后放在controller里调用即可
然后我们设置id为自增规则,并且表数据为倒叙排序,此时我们新增数据功能就完成了:
注意:若想让数据按id倒叙排序,不能并列式的写LambdaQuery,要单独起一行
我们输入数据即可在数据库中插入数据(id不是随机且自增)
接下来我们来实现编辑按钮:
在vue3中不能使用 slot-scope 在vue3中用#相当于vue2中的slot=
(94条消息) vue3的slot插槽用法,`slot-scope` are deprecated_浩星的博客-CSDN博客_`slot-scope` are deprecated
这个时候我们就可以打开这个数据的el-dialog 点击保存即可完成编辑
删除:
编写业务层接口:
这里写错了,应该用RemoveById方法
编写控制层的接口:
增加一个气泡弹出窗口用来确定是都真正删除
您确定删除吗?
我再想想
确认
删除
注意不要忘了在templete标签里写#reference 不然按钮会不显示
多选:
在e-table标签下加入一行代码,并且在e-table标签里写入
@selection-change="handleSelectionChange
之后编写批量删除的接口
//批量删除的接口
@DeleteMapping("/del/batch")
public boolean deleteBatch(@RequestBody List ids){
return userService.removeByIds(ids);
}
在vue里编写delBatch方法
delBatch(){
let ids = this.multipleSelection.map(v => v.id)
console.log(ids)//[{}.{}.{}] => [1,2,3]
request.delete("http://localhost:8081/del/batch",{data:ids}).then(res => {
if(res){
this.$message.success("批量删除成功")
}else{
this.$message.error(("批量删除失败"))
}
this.load();
})
}
设置批量删除气泡弹窗,并绑定事件
您确定批量删除数据吗?
我再想想
确认
批量删除
效果:
优化:
发现:如果不把load()重新加载数据放在最后一行,在新增操作保存后多选数据气泡窗口可能不显示
新增多选按钮,点击出现多选框,再次点击隐藏
给多选框绑定v-if
将letapear初始值默认为false
设置多选按钮 用双括号绑定名称
{{duoxuan}}
编写方法:
Apearselection(){
if(!this.letapear){
this.letapear=true;
this.duoxuan="取消多选"
}else{
this.letapear=false;
this.duoxuan="多选"
}
}
效果:
1、封装侧边栏
新建一个Aside.vue将以下代码(e-menu)从menage.vue移动到里面
然后再AsideView里面编写props将用到的原来组件的参数传入进来,并且编写components将原来用到的组件传递过来
然后在原来的界面引入AsideView组件,并且使用该组件
e-side我们就转移完毕了
然后我们转移e-header
将e-header代码转移到HeaderView里面,然后将style样式做部分迁移,因为转移后,都放在外面不好使。
然后本来collapse方法在原来的主vue里面,所以我们要定义一个方法,并且通过$emit
将本组件的请求发送过去:
然后再在主vue引入我们的header,并且在header里面连接方法
这样header就拆装完毕了
之后我们再把e-main拿出来单独封装
之后将e-main里面的代码放在里面
主页
用户管理
promotion list
promotion detail
搜索
重置
新增
{{duoxuan}}
您确定批量删除数据吗?
我再想想
确认
批量删除
导入
导出
编辑
您确定删除吗?
我再想想
确认
删除
再把meanagor组件的大部分方法和属性和组件(除了折叠的方法,和用到的属性,其它都迁移到TableView里面)
然后把TableView放在路由里面:作为
它的子路由,这样就可以通过主路由加载子路由的方式拼装整个页面,这样侧边栏就会一直出现在页面里供我们操作
我们也定义一个home放在里面当子路由:
设置重定向:
之后我们就可以通过路由入口的方式把路由入口router-view放在父组件需要加载子组件的地方
这样我们就可以通过访问子路由的方式 让整个页面加载
至此我们就把整个menager组件的所有功能拆分开成不同的组件,这样方便管理,方便维护更改
然后我们设置侧边栏点击可以跳转我们之前设置的两个路由界面:home,table
这个很简单我们只需要更改el-menu-item标签里的 index即可
不过在此之前一定要记得把e-menu里面的router属性自己手动设为true ,它默认为false
这样我们就实现了点击侧边栏跳转到我们设置的路由
之后我们实现导入导出功能
这个功能要依赖于hutool,所以我们导入以下依赖
cn.hutool
hutool-all
5.7.20
org.apache.poi
poi-ooxml
4.1.2
hutool官网;Hutool — A set of tools that keep Java sweet.
Excel工具-ExcelUtil (hutool.cn)
在getwriter参数里面可以写输出路径,我们这里不写,为了在浏览器直接点击下载
在控制类里封装一个export接口
//导出的接口
@GetMapping("/export")
public void export(HttpServletResponse response)throws Exception{
//从数据库中查出所有的数据
Listlist = userService.list();
//通过工具类创建writer 写出到磁盘路径
// ExcelWriter writer = ExcelUtil.getWriter(filesUploadPath+"/用户信息.xlsx");
//在内存操作,写出到浏览器
ExcelWriter writer = new ExcelUtil().getWriter(true);
//自定义标签别名
writer.addHeaderAlias("username","用户名");
writer.addHeaderAlias("password","密码");
writer.addHeaderAlias("nickname","昵称");
writer.addHeaderAlias("email","邮箱");
writer.addHeaderAlias("address","地址");
writer.addHeaderAlias("createTime","创建时间");
writer.addHeaderAlias("avatarUrl","头像");
//一次性写出list内的对象到excel,使用默认样式,强制输出标题
writer.write(list,true);
//设置浏览器响应的格式
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
String fileName = URLEncoder.encode("用户信息","UTF-8");
response.setHeader("Content-Disposition","attachment;filename="+fileName+".xlsx");
ServletOutputStream out = response.getOutputStream();
writer.flush(out,true);
out.close();
writer.close();
}
设置登陆注册页面
登录页面:
(95条消息) Vue3+SpringBoot实现【登录】【毛玻璃】【渐变色】_白开水为啥没味的博客-CSDN博客
注册页面
复制登陆界面作为注册界面,给注册界面添加路由,编写接口
增加确认密码,并更改按钮,添加事件,具体代码如下
注册
注册
返回登录
绑定头像和昵称:
首先在数据库添加字段:
注意要按照驼峰映射来命名,如数据库中用两个小写单词中间用下划线隔开命名
实体类中的属性名称用小写单词加大写单词命名
在实体类添加字段
user
userDto
绑定前端数据(头像图片和用户昵称)
编写获取user对象 信息(账号,邮箱,昵称,头像连接)
注意,在退出的时候清楚缓存
效果:
组件命名最好符合驼峰映射:
驼峰映射: