1. Element介绍
Element:是饿了么公司前端开发团队提供的一套基于 Vue 的网站组件库,用于快速构建网页。
Element 提供了很多组件(组成网页的部件)供我们使用。例如 超链接、按钮、图片、表格等等。如下图所示就是我们开发的页面和ElementUI提供的效果对比:可以发现ElementUI提供的各式各样好看的按钮
2. 快速入门
首先,我们先要安装ElementUI的组件库,打开VS Code,停止之前的项目,然后在命令行输入如下命令:
npm install element-ui@2.15.3
具体操作如下图所示:
然后我们需要在main.js这个入口js文件中引入ElementUI的组件库,其代码如下:
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI);
然后我们需要按照vue项目的开发规范,在src/views目录下创建一个vue组件文件,注意组件名称后缀是.vue,并且在组件文件中编写之前介绍过的基本组件语法,代码如下:
最后我们只需要去ElementUI的官网,找到组件库,然后找到按钮组件,抄写代码即可,具体操作如下图所示:
找到相应部分的代码复制就OK了
最后,我们需要在默认访问的根组件src/App.vue中引入我们自定义的组件,具体操作步骤如下:
然后App.vue组件中的具体代码如下,代码是我们通过上述步骤引入element-view组件时自动生成的。
<template>
<div id="app">
{{ message }}
<element-view></element-view>
</div>
</template>
<script>
import ElementView from './views/ElementView.vue';
export default {
components: { ElementView },
data() {
return {
message: "Hello Vue",
};
},
};
</script>
<style>
</style>
然后运行我们的vue项目,浏览器直接访问之前的7000端口,展示效果如下图所示:
到此,我们ElementUI的入门程序编写成功
3. 案例
该案例将使用 王者 数据,具体数据可查看 juejin.cn/post/742141…
在此基础上进行改造,我们再添加新的API,主要添加分页插件
添加全局统一返回结果类Result和统一返回结果状态信息枚举类ResultCodEnum
ResultCodEnum代码如下:
package org.example.utils;
/**
* @Author 烔
* @date 2024/10/7
* @Description 统一返回结果状态信息枚举类
*/
public enum ResultCodEnum {
SUCCESS(200,"success"),
USERNAME_ERROR(501,"usernameError"),
PASSWORD_ERROR(503,"passwordError"),
NOTLOGIN(504,"notLogin"),
USERNAME_USED(505,"userNameUsed"),
UPDATE_FAILED(400, "failed");
private Integer code;
private String message;
private ResultCodEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
}
Result代码如下:
package org.example.utils;
/**
* @Author 烔
* @date 2024/10/7
* @Description 全局统一返回结果类
*/
public class Result<T> {
private Integer code;
private String message;
private T data;
public Result() {
}
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<>();
if (data != null) {
result.setData(data);
}
return result;
}
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
return result;
}
public static <T> Result<T> build(T body, ResultCodEnum resultCodEnum) {
Result<T> result = build(body);
result.setCode(resultCodEnum.getCode());
result.setMessage(resultCodEnum.getMessage());
return result;
}
/**
* 操作成功
* @return
*/
public static <T> Result<T> ok(T data){
Result<T> result = build(data);
return build(data,ResultCodEnum.SUCCESS);
}
public Result<T> message(String msg){
this.setCode(code);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
在Main中添加分页拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
// 创建 MybatisPlusInterceptor 对象
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 添加分页拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 返回配置好的 MybatisPlusInterceptor 对象
return mybatisPlusInterceptor;
}
在HeroController中添加以下代码:
@GetMapping("SelectPage")
public Result selectPage(@RequestParam("page") Integer page, @RequestParam("limit") Integer limit) {
Page<Hero> heroPage = new Page<>(page, limit);
Page<Hero> ipage = heroMapper.selectPage(heroPage, null);
Map<String, Object> result = new HashMap<>();
result.put("total", ipage.getTotal());
result.put("page", ipage.getPages());
result.put("pageSize", ipage.getSize());
result.put("currentPage", ipage.getCurrent());
List<Hero> records = ipage.getRecords();
result.put("records", ipage.getRecords());
return Result.ok(result);
}
访问 http://localhost:8080/hero/SelectPage 后添加请求参数后就获取到数据了,eg:http://localhost:8080/hero/SelectPage?page=1&limit=20
后端代码到此最终完成
下面开始前端代码(完整代码将附在最后):
创建HeroView.vue
选择心仪的布局容器样式并复制相应代码:
<el-container>
<el-header>Header</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
在App.vue中引用HeroView.vue
<template>
<div id="app">
<hero-view></hero-view>
</div>
</template>
<script>
import HeroView from './views/HeroView.vue';
export default {
components: { HeroView },
data() {
},
};
</script>
<style>
</style>
到这里基本的容器布局完成
<template>
<el-container>
<el-header>王者英雄信息</el-header>
<el-container>
<el-aside width="200px">Aside</el-aside>
<el-main>Main</el-main>
</el-container>
</el-container>
</template>
<script>
</script>
<style>
.el-header,
.el-footer {
background-color: #b3c0d1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #d3dce6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #e9eef3;
color: #333;
text-align: center;
line-height: 160px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
</style>
设置Aside代码:
<el-menu :default-openeds="['1', '3']">
<el-submenu index="2">
<template slot="title"><i class="el-icon-menu"></i>导航二</template>
<el-menu-item index="2-1">选项1</el-menu-item>
<el-menu-item index="2-2">选项2</el-menu-item>
</el-submenu>
</el-menu>
设置Main
<el-container>
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>查看</el-dropdown-item>
<el-dropdown-item>新增</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>用户登录名</span>
</el-header>
<el-main>
<el-table :data="tableData">
<el-table-column prop="heroId" label="英雄ID" width="140">
</el-table-column>
<el-table-column prop="name" label="英雄姓名" width="120">
</el-table-column>
<el-table-column prop="cover" label="英雄图片"> </el-table-column>
</el-table>
</el-main>
<div class="block">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage4"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400"
>
</el-pagination>
</div>
</el-container>
访问数据(script标签代码)
import axios from "axios";
export default {
data() {
return {
tableData: [],
currentPage: 1,
pageSize: 6,
total: 400,
};
},
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageSize = val;
this.feachHeroInfo();
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.currentPage = val;
this.feachHeroInfo();
},
feachHeroInfo() {
axios
.get("http://localhost:8080/hero/SelectPage", {
params: {
page: this.currentPage,
limit: this.pageSize,
},
})
.then((res) => {
this.tableData = res.data.data.records;
this.total = res.data.data.total;
});
},
},
mounted(){
this.feachHeroInfo();
}
};
至此,数据访问成功!!!
下面进行页面样式调整(根据自己喜好进行调整)
<template>
<el-container>
<el-header style="font-size: 40px">王者英雄信息</el-header>
<el-container>
<el-aside width="200px">
<el-menu :default-openeds="['1', '3']">
<el-submenu index="2">
<template slot="title"><i class="el-icon-menu"></i>导航二</template>
<el-menu-item index="2-1">选项1</el-menu-item>
<el-menu-item index="2-2">选项2</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<el-container>
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>查看</el-dropdown-item>
<el-dropdown-item>新增</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>用户登录名</span>
</el-header>
<div class="user-info-table">
<el-main>
<el-table :data="tableData" border :row-class-name="tableRowClassName" :header-cell-style="{ height: '50px', lineHeight: '50px' }">
<el-table-column prop="heroId" label="英雄ID" width="140">
</el-table-column>
<el-table-column prop="name" label="英雄姓名" width="120">
</el-table-column>
<el-table-column prop="cover" label="英雄图片"> </el-table-column>
</el-table>
</el-main>
</div>
<div class="block">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="1"
:page-sizes="[5, 10, 15, 20]"
:page-size="5"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</div>
</el-container>
</el-main>
</el-container>
</el-container>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
tableData: [],
currentPage: 1,
pageSize: 6,
total: 400,
};
},
methods: {
handleSizeChange(val) {
console.log(`每页 ${val} 条`);
this.pageSize = val;
this.feachHeroInfo();
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`);
this.currentPage = val;
this.feachHeroInfo();
},
feachHeroInfo() {
axios
.get("http://localhost:8080/hero/SelectPage", {
params: {
page: this.currentPage,
limit: this.pageSize,
},
})
.then((res) => {
this.tableData = res.data.data.records;
this.total = res.data.data.total;
});
},
tableRowClassName({ rowIndex }) {
if (rowIndex % 2 === 1) {
return "warning-row";
} else if (rowIndex % 2 === 0) {
return "success-row";
}
return "";
},
},
mounted() {
this.feachHeroInfo();
},
};
</script>
<style>
html,
body {
width: 100%;
height: 100vh;
margin: 0;
padding: 0;
/* overflow: hidden; */
}
.el-header,
.el-footer {
background-color: #b3c0d1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #d3dce6;
color: #333;
text-align: center;
line-height: 200px;
}
.el-main {
background-color: #e9eef3;
color: #333;
text-align: center;
line-height: 160px;
}
body > .el-container {
margin-bottom: 40px;
}
.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
line-height: 260px;
}
.el-container:nth-child(7) .el-aside {
line-height: 320px;
}
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
.user-info-table {
flex: 1;
padding: 0;
margin: 0;
width: 100%;
height: 440px;
overflow: auto;
}
.block{
padding: 0;
margin: 0;
width: 100%;
}
</style>
图片内容展示修复
<el-table-column prop="cover" label="英雄图片">
<template slot-scope="scope">
<img :src="scope.row.cover" width="100px" height="100px">
</template>
</el-table-column>
将表格绑定在导航栏中
<div class="user-info-table">
表格和分页插件代码
</div>
<script>
method:{
handleMenuSelect(index) {
if (index === "2-1") {
this.showHeroInfoTable = true;
this.showimg = false;
} else {
this.showHeroInfoTable = false;
this.showimg = true;
}
},
}
</script>
完整效果图:
4.Vue路由
vue官方提供了路由插件Vue Router,其主要组成如下:
- VueRouter:路由器类,根据路由请求在路由视图中动态渲染选中的组件
- :请求链接组件,浏览器会解析成
<a> - :动态视图组件,用来渲染展示与路由路径对应的组件
其工作原理如下图所示:
前端路由:URL中的hash(#号之后的内容)与组件之间的对应关系,
首先VueRouter根据我们配置的url的hash片段和路由的组件关系去维护一张路由表;
然后我们页面提供一个组件,用户点击,发出路由请求;
接着我们的VueRouter根据路由请求,在路由表中找到对应的vue组件;
最后VueRouter会切换中的组件,从而进行视图的更新
路由入门
接下来我们来演示vue的路由功能。
首先我们需要先安装vue-router插件,可以通过如下命令
npm install vue-router@3.5.1
但是我们不需要安装,因为当初我们再创建项目时,已经勾选了路由功能,已经安装好了。
然后我们需要在src/router/index.js文件中定义路由表,根据其提供的模板代码进行修改,最终代码如下:
import Vue from 'vue'
import VueRouter from 'vue-router'
import ElementView from '../views/ElementView.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/elementView',
name: 'elementView',
component: ElementView
},
{
path: '/hero',
name: 'hero',
component: () => import('../views/HeroView.vue')
}
]
const router = new VueRouter({
routes
})
export default router
注意需要去掉没有引用的import模块。
在main.js中,我们已经引入了router功能,如下图所示:
路由基本信息配置好了,路由表已经被加载,此时我们还缺少2个东西,就是<router-lin>和<router-view>,所以我们需要修改2个页面(HeroView.vue和ElementView.vue)我们左侧栏的2个按钮为router-link,其代码如下:
<el-menu-item index="2-1">
<router-link to="/hero">王者</router-link>
</el-menu-item>
<el-menu-item index="2-2">
<router-link to="elementView">elementView</router-link>
</el-menu-item>
然后我们还需要在内容展示区域即App.vue中定义route-view,作为组件的切换,其App.vue的完整代码如下:
然后我们还需要在内容展示区域即App.vue中定义route-view,作为组件的切换,其App.vue的完整代码如下:
<template>
<div id="app">
<!-- <hero-view></hero-view>-->
<router-view></router-view>
</div>
</template>
<script>
// import HeroView from './views/HeroView.vue';
export default {
components: {},
data() {
},
};
</script>
<style>
</style>
但是我们浏览器打开地址: http://localhost:7000/ ,发现一片空白,因为我们默认的路由路径是/,但是路由配置中没有对应的关系,
所以我们需要在路由配置中/对应的路由组件,代码如下:
import Vue from 'vue'
import VueRouter from 'vue-router'
import ElementView from '../views/ElementView.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/elementView',
name: 'elementView',
component: ElementView
},
{
path: '/hero',
name: 'hero',
component: () => import('../views/HeroView.vue')
}, {
path: '/',
redirect: '/hero' // 表示重定向到/hero即可
}
]
const router = new VueRouter({
routes
})
export default router
到此我们的路由实现成功。