最后
由于篇幅限制,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
import Main from “…/views/Mian.vue”;
// 主页面
// 1.创建路由组件,也就是我们创建views里面的组件文件
// 引入我们创建的vue组件文件
import Home from “…/views/Home.vue”;
import User from “…/views/User.vue”;
import Mall from “…/views/Mall.vue”;
import qtPageOne from “…/views/qtPageOne.vue”;
import qtPageTow from “…/views/qtPageTow.vue”;
// 2. 定义路由
// 将路由与组件进行映射
const routes = [
// 主页面
{
path: “/”,
// /默认是主出口主页面组件
redirect:‘home’,
// 重定向到home
component: Main,
children: [
// 子路由
{ path: “home”, component: Home },
// 首页
{ path: “user”, component: User },
// 用户管理
{ path: “mall”, component: Mall },
// 商品管理
{ path: “page1”, component: qtPageOne },
// 其他页面1
{ path: “page2”, component: qtPageTow },
// 其他页面2
],
},
];
// 3. 创建 router 实例,然后传routes配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes, // (缩写) 相当于 routes: routes
});
// 导出我们的router实例
export default router;
文件结构
![在这里插入图片描述](https://img-blog.csdnimg.cn/93d91eaccc2345bd9045e0cfac4c1c43.png#pic_center)
###### 4.5.2、点击菜单,根据点击菜单的数据跳转应路由页面\*\*
v-for=“item in menuHasChildren”
:key=“item.label”
:index=“item.label”
<template slot="title">
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{ item.label }}</span>
</template>
<!-- 遍历生成有二级菜单的子菜单 -->
<el-menu-item-group v-for="subItem in item.children" :key="subItem.path">
<!-- 子菜单渲染 -->
<!-- clickMenu跳转 -->
<el-menu-item @click="clickMenu(subItem)" :index="subItem.path">{{ subItem.label }}</el-menu-item>
</el-menu-item-group>
</el-submenu>
**效果**
![在这里插入图片描述](https://img-blog.csdnimg.cn/915cb823c3b6485a85f1191272d49fae.png#pic_center)
### 5、通用管理后台(header组件与样式搭建)
##### 5.1、封装header区域组件与样式
菜单区域我们已经完成了,接下来我们完成一下header区域的布局和样式编写,一个是左侧的按钮区域和面包屑区域,另外就是用户头像区域带下来菜单。
封装创建一个CommonHeader.vue
![](../assets/tx.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/aa0c96dbd9c6401683ae4c98383586a1.png#pic_center)
在Main.vue中引入并且使用
Main.vue
<!-- router-view Main下面子路由的路由出口 -->
<router-view>
</router-view>
</el-main>
</el-container>
</el-container>
}
}
}
**效果**
![在这里插入图片描述](https://img-blog.csdnimg.cn/1142ccc553914e52ac94bf5ce411f1a9.png#pic_center)
##### 5.2、通过vuex实现左侧折叠
前面已经完善了header区域的布局和样式,接下来把header区域按钮的点击操作菜单折叠与展开完善一下!但是按钮在CommonHeader.vue组件中,那么如何去操作CommonAside.vue菜单组件呢?
![在这里插入图片描述](https://img-blog.csdnimg.cn/42dff2cbb51c4a7c924011df761e8e5c.png#pic_center)
因为状态修改牵扯到俩个组件中的变化,接下来我们就用vuex去实现
###### 5.2.1、什么是vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex分为俩个比较大的版本,一个是4.0(主要针对于vue3),一个3.0(主要针对vue2),
[Vuex4官网](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)
[Vuex3官网](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)
![在这里插入图片描述](https://img-blog.csdnimg.cn/32ad82dde5954c7097055e921aac5aee.png#pic_center)
###### 5.2.2、安装vuex
npm i vuex@3.6.2
![在这里插入图片描述](https://img-blog.csdnimg.cn/b58ab925778249759c8385f52d901c18.png#pic_center)
###### 5.2.3、配置vuex
在src文件下创建一个store文件夹,在store新建一个index.js文件配置vuex
因为菜单和用户是俩部分单独的一块信息,对于这种数据,按照模块化的思想,把它拆分成俩个 modules
新建一个tab.js用于管理菜单的数据
// 管理菜单的数据
export default{
state:{
isCollapse:false,
// isCollapse用于控制菜单的展开和收起
},
mutations:{
// 修改菜单展开收起方法
collapseMenu(state){
state.isCollapse=!state.isCollapse
}
}
}
``
在store下面的index.js配置vuex和注入`
// 引入vue
import Vue from 'vue'
import Vuex from 'vuex'
import tab from './tab'
// 引入管理菜单的数据
Vue.use(Vuex)
// 将Vuex全局注入
// 创建vuex实例
export default new Vuex.Store({
modules:{
tab
}
})
在mian.js将我们的vuex实例挂载到vue上
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 引入element-ui样式文件
import router from './router'
// 引入路由文件
import store from'./store'
Vue.config.productionTip = false
Vue.use(ElementUI);
// 全局注入element-ui
new Vue({
router,
// 挂载router实例
store,
// 挂载vuex实例
el: '#app',
render: h => h(App),
}).$mount('#app')
5.2.4、使用vuex
在我们组件中使用vuex完成我们的点击按钮让菜单展开收起的功能
在CommonHeader.vue中点击按钮调用mutations方法修改vuex中state里isCollapse数据
CommonHeader.vue
HandelMenu方法使我们点击按钮事件方法
<template>
<div class="header-content">
<!-- 头部组件 -->
<div class="l-content">
<!-- 左侧 -->
<!-- icon的按钮 ,HandelMenu点击按钮方法 -->
<el-button @click="HandelMenu" icon="el-icon-menu" size="mini"></el-button>
<!-- 面包屑,先用span标签代替 -->
<span class="text">首页</span>
</div>
<div class="r-content">
<!-- 右侧 -->
<!-- el-dropdown 下拉菜单-->
<el-dropdown>
<img class="user" src="../assets/tx.png" alt="">
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item>退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</template>
<script>
export default {
data() {
return {};
},
methods:{
HandelMenu(){
// 按钮点击事件,调用vuex的mutations方法
this.$store.commit('collapseMenu')
}
}
};
</script>
<style lang="less" scoped>
.header-content {
padding: 0 20px;
background-color: #333;
height: 60px;
display: flex;
justify-content: space-between;
align-items: center;
.text {
color: white;
font-size: 14px;
margin-left: 10px;
}
.r-content{
.user{
// 头像
width: 40px;
height: 40px;
border-radius: 50%;
}
}
}
</style>
CommonAside.vue
获取vuex的state中的isCollapse数据,绑定我们菜单实现菜单展开和收缩
在computed属性中进行使用的
<template>
<el-menu
default-active="1-4-1"
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
:collapse="isCollapse"
background-color="#545c64"
text-color="#fff"
active-text-color="#ffd04b"
>
<h3>vue前端通用管理后台</h3>
<!-- 点击菜单选项触发clickMenu事件 -->
<el-menu-item
@click="clickMenu(item)"
v-for="item in menuNoChildren"
:key="item.name"
:index="item.name"
>
<!-- 遍历生成无子菜单数据 -->
<i :class="`el-icon-${item.icon}`"></i>
<!-- i标签是渲染的element-ui的图标,使用了es6中的自符模板 -->
<span slot="title">{{ item.label }}</span>
<!-- span 标签是菜单名字 -->
</el-menu-item>
<!-- 遍历生成有二级菜单的一级菜单菜单 -->
<el-submenu
v-for="item in menuHasChildren"
:key="item.label"
:index="item.label"
>
<template slot="title">
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{ item.label }}</span>
</template>
<!-- 遍历生成有二级菜单的子菜单 -->
<el-menu-item-group v-for="subItem in item.children" :key="subItem.path">
<!-- 子菜单渲染 -->
<!-- clickMenu跳转 -->
<el-menu-item @click="clickMenu(subItem)" :index="subItem.path">{{ subItem.label }}</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</template>
<style scoped lang="less">
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
// 菜单高度和标题样式
.el-menu {
height: 100vh;
border-right: none;
h3 {
margin: 0;
color: white;
text-align: center;
line-height: 48px;
font-size: 16px;
font-weight: 400;
}
}
</style>
<script>
export default {
data() {
return {
// menuData 菜单数据
menuData: [
{
path: "/",
name: "home",
label: "首页",
icon: "s-home",
url: "Home/Home",
},
{
path: "/mall",
name: "mall",
label: "商品管理",
icon: "video-play",
url: "MallManage/MallManage",
},
{
path: "/user",
name: "user",
label: "用户管理",
icon: "user",
url: "UserManage/UserManage",
},
{
label: "其他",
icon: "location",
children: [
{
path: "/page1",
name: "page1",
label: "页面1",
icon: "setting",
url: "Other/PageOne",
},
{
path: "/page2",
name: "page2",
label: "页面2",
icon: "setting",
url: "Other/PageTwo",
},
],
},
],
};
},
methods: {
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
// 点击菜单,跳转
clickMenu(item) {
// item 触发传递的数据
console.log(item.path);
// 添加容错逻辑
// 当我们的路由与我们跳转的路由不一致时,才允许跳转
// 当前页面路由
if(this.$route.path!=item.path &&!(this.$route.path==='/home'&&(item.path==='/'))){
this.$router.push(item.path);
}
},
},
computed: {
// computed计算属性
// 对menuData菜单数据进行过滤,分组
// 1.没有子菜单、
menuNoChildren() {
return this.menuData.filter((item) => !item.children);
},
// 2.有子菜单
menuHasChildren() {
return this.menuData.filter((item) => item.children);
},
// 在computed属性下
isCollapse(){
return this.$store.state.tab.isCollapse
// 我们state的isCollapse数据
//false展开,true收起
}
},
};
</script>
效果
展开
收缩=>可以看到有bug
5.3、解决菜单收缩展开的bug
利用三元判断修改左侧收起标题问题
<h3>{{isCollapse?'vue前端通用管理后台':'后台'}}</h3>
宽度问题
Main.vue中el-aside 将之前我们设置的width="200px"值改为auto自适应
<el-aside width="auto">
<!-- 把引入的CommonAside菜单组件进行使用 -->
<CommonAside/>
</el-aside>
效果
5、通用管理后台(home组件与样式搭建)
关于home组件包含左侧用户信息和table数据,右侧是订单数据加上折线图柱状图饼状图,并且自适应布局(使用element-ui中的layout布局),鼠标移入区域有阴影(element-ui中的card组件)
5.1、home组件布局
5.1.1、home组件–左侧用户信息
Home.vue
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt="">
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>上次登录时间:<span>2023-3-29</span></p>
<p>上次登录地点:<span>中山</span></p>
</div>
</el-card>
</el-col>
<el-col :span="16"></el-col>
</el-row>
</template>
<script>
export default {
data() {
return {};
}
};
</script>
<style lang="less" scoped>
.user{
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img{
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail{
// 用户详情信息
.name{
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access{
// 角色
color: #999;
}
}
}
.user-info{
// 登录时间和地点
p{
line-height: 28px;
font-size: 14px;
color: #999;
span{
color: #666;
margin-left: 60px;
}
}
}
</style>
效果
5.1.2、home组件–左侧table表格信息
对于table在后台管理中是一个用的比较多点,基本每个后台都有,像列表页信息的展示等等,我们使用element-ui组件库中的el-table实现
表格数据
tableData: [
{
name: "HTML",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "CSS",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "JavaScript",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "Vue",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "React",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "微信小程序",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
],
Home.vue表格=>(静态)
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>
</el-card>
</el-col>
<el-col :span="16"></el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
// tableData表格数据
tableData: [
{
name: "HTML",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "CSS",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "JavaScript",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "Vue",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "React",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "微信小程序",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
],
};
}
};
</script>
<style lang="less" scoped>
.user {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img {
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail {
// 用户详情信息
.name {
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access {
// 角色
color: #999;
}
}
}
.user-info {
// 登录时间和地点
p {
line-height: 28px;
font-size: 14px;
color: #999;
span {
color: #666;
margin-left: 60px;
}
}
}
</style>
Home.vue表格=>(动态)
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table> -->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16"></el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
// tableData表格数据
tableData: [
{
name: "HTML",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "CSS",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "JavaScript",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "Vue",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "React",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "微信小程序",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: '技术栈',
todayBuy: '今日学习人数',
monthBuy: '本月学习人数',
totalBuy: '学习总数据'
},
};
}
};
</script>
<style lang="less" scoped>
.user {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img {
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail {
// 用户详情信息
.name {
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access {
// 角色
color: #999;
}
}
}
.user-info {
// 登录时间和地点
p {
line-height: 28px;
font-size: 14px;
color: #999;
span {
color: #666;
margin-left: 60px;
}
}
}
</style>
效果
5.1.3、home组件–右侧学习数据统计实现
前面我们已经完成了左侧布局和table数据展示,图表使用了es6模板字符串拼接类名结合element的图表实现的
Home.vue=>class="num"盒子
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>-->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16">
<!-- 右侧区域 -->
<div class="num">
<el-card :body-style="{display:'flex',padding:0}" v-for="item in countData" :key="item.name">
<i :style="{background:item.color}" class="icon" :class="`el-icon-${item.icon}`"></i>
<div class="detail">
<p class="dataPrice">{{ item.value }}</p>
<p class="dataDesc">{{ item.name }}</p>
</div>
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
export default {
data() {
return {
// tableData表格数据
tableData: [
{
name: "HTML",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "CSS",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "JavaScript",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "Vue",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "React",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: "微信小程序",
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: "技术栈",
todayBuy: "今日学习人数",
monthBuy: "本月学习人数",
totalBuy: "学习总数据"
},
// countData 学习数据统计
countData: [
{
name: "今日学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "今日收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "今日查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
},
{
name: "本月学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "本月收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "本月查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
}
]
};
}
};
</script>
<style lang="less" scoped>
.user {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img {
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail {
// 用户详情信息
.name {
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access {
// 角色
color: #999;
}
}
}
.user-info {
// 登录时间和地点
p {
line-height: 28px;
font-size: 14px;
color: #999;
span {
color: #666;
margin-left: 60px;
}
}
}
// 右侧学习数据
.num {
display: flex;
flex-wrap: wrap; // 强制换行
justify-content: space-between;
.icon {
// 图表
width: 80px;
height: 80px;
font-size: 30px;
text-align: center;
line-height: 80px;
color: white;
}
.detail{
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 15px;
.dataPrice{
font-size: 30px;
margin-bottom: 10px;
line-height: 30px;
height: 30px;
}
.dataDesc{
color: #999;
font-size: 14px;
text-align: center;
}
}
.el-card{
// 右侧卡片
width: 32%;
margin-bottom: 20px;
}
}
</style>
效果
6、通用管理后台(Axios 和Mock.js模拟数据)
那么接下来我们继续完成剩下的图表展示部分,我们除了图表的展示,另外呢就是图表的数据,不过在这个到目前为止,我们的数据还都是写死的,那么在我们实际项目开发中,我们的数据一般是由后端返回给我们的,后端经过逻辑处理然后返回给我们
Axios 文档
6.1、扩展–前后端联调
在我们开发的页面中,我们的代码都是运行在游览器上的,那我们想获取数据,具体步骤是游览器向服务器发送一个ajax请求,服务器接收到请求之后之后,将数据回传给游览器
发送请求有很多种方式,比如原生js的XMLHttpRequest对象实现ajax请求,当然这种实现方式是比较复杂的,但是在项目开发中,我们更多的是使用工具或者第三方库来完成我们这些功能,接下来就介绍一个非常使用的axios插件
6.2、Axios
Axios 相对于我们原生js的XMLHttpRequest,Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。从写法上可以避免回调地狱的问题,因为我们可以通async和await这俩种写法结合我们promise 将整个异步的过程转换成同步的写法,另外Axios 封装了一些比较好用的api,我们可以直接调用它,实现我们一些一些接口请求的封装、公共的请求头等等
6.2.1、Axios 的基本使用
安装:
npm install axios
在项目文件下进行安装
6.2.2、Axios 的二次封装
安装完成之后,我们要使用axios做接口请求,在我们项目中接口是非常多的,我们要对这些进行一个二次封装,我们封装的就是 Axios 的实例,axios.create这个方法会返回一个实例,我们拿到这些实例之后,就可以调用这些实例的方法,这些实例的方法就具备我们创建Axios时配置的一些属性,对于这些实例我们还可以配置个拦截器(请求拦截器和响应拦截器) ,请求拦截器在发送请求之前进行的一些处理(像header请求头的内容token等等),响应拦截器是服务器端回传消息给我们的时候,在我们拿到数据之前可以做哪些处理 (像http的状态码,像非200的状态码可以给用户一些提示或者对业务数据进行逻辑判断等等,), 把相对繁琐的的一些请求进行一下处理。
接下来我们就完成Axios 在项目中的一个封装
在src文件夹下面新建一个utils文件夹用于做数据处理文件的文件夹
utils文件夹=>新建一个requerst.js文件
这里对拦截器没有过多地封装,大家可以根据自己需要网上找一下即可
import axios from 'axios'
// 引入axios
const http=axios.create({
baseURL:'/api',
// baseURL通用请求地址(地址前缀),这个地址根据实际项目中更改成自己的即可
timeout:10000,
// timeout 请求超时时间 单位是毫秒
// 其余配置如果需要可参考axios文档进行配置=>http://www.axios-js.com/zh-cn/docs/vue-axios.html
})
// 拦截器
// 添加请求拦截器
http.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
http.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default http
6.2.3、api调用接口文件封装
在src文件夹下面新建一个api文件夹用于放封装的接口调用文件
api文件夹=>新建index.js
因为涉及接口比较少,就以index.js做演示,后续大家可以根据项目需要进行一下分类单独封装
import http from "@/utils/request";
// 引入我们二次封装的axios实例
// 接口调用封装
// 请求首页数据
export const getData=()=>{
// /home/getData接口地址
// 返回一个promise对象
return http.get('/home/getData')
}
在页面中使用封装封装好的请求接口方法
<script>
import {getData} from '../api'
// 引入封装好的请求方法
export default {
data() {
return {
},
mounted(){
// mounted挂载
getData().then(res=>{
//使用getData封装方法
console.log(res)
})
}
};
</script>
结果
可以看到发送了请求,目前只是我们还没有后端服务,所以会报404的错误,不过从这里我们已经完成了Axios的二次封装,并且发送了请求
因为上面没有后端服务,那么接下来就简单介绍一下mock数据,模拟后端接口,实现交互
6.3、Mock.js
在没有后端提供数据的情况下,前端人员在自己写demo或者练手项目的时候可以使用mock.js来模拟数据
Mock是一个前端模拟后端接口的一个工具,我们可以通过拦截前端发起的请求,可以自己定义一些返回的数据,这种情况下是我们在不依赖后端的情况下,实现数据交互
6.3.1、Mock.js安装
# 安装
npm install mockjs
在项目文件下进行安装
6.3.2、Mock.mock()方法
Mock.mock()方法参数以及使用
Mock.mock( rurl?, rtype?, template|function( options ) )
6.3.3、Mock使用
api文件夹=>新建mock.js
import Mock from 'mockjs'
// 引入mock
// 定义mock接口请求拦截
/\*\*
\* Mock.mock参数
\* 第一个是拦截接口的地址
\* 第二个是接口请求类型(可省略)
\* 第三个是一个函数=>拦截后的请求逻辑
\*/
Mock.mock('/api/home/getData','get',function(){
// 拦截后的请求逻辑
console.log('拦截到了')
})
在main.js引入mock处理文件
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// 引入element-ui样式文件
import router from './router'
// 引入路由文件
import store from'./store'
// 引入mock处理文件
import './api/mock'
Vue.config.productionTip = false
Vue.use(ElementUI);
// 全局注入element-ui
new Vue({
router,
// 挂载router实例
store,
// 挂载vuex实例
el: '#app',
render: h => h(App),
}).$mount('#app')
效果
以上是完成了第一步,对mock进行简单的使用,接下来就正式模拟接口和数据
6.3.4、Mock模拟接口数据
api文件夹=>新建mockServeData文件夹
用于存放对应页面模拟数据文件
mockServeData文件夹=>新建home.js
存放首页mock数据
// mock数据模拟
import Mock from 'mockjs'
// 图表数据
let List = []
export default {
getStatisticalData: () => {
//Mock.Random.float 产生随机数100到8000之间 保留小数 最小0位 最大0位
for (let i = 0; i < 7; i++) {
List.push(
Mock.mock({
苹果: Mock.Random.float(100, 8000, 0, 0),
vivo: Mock.Random.float(100, 8000, 0, 0),
oppo: Mock.Random.float(100, 8000, 0, 0),
魅族: Mock.Random.float(100, 8000, 0, 0),
三星: Mock.Random.float(100, 8000, 0, 0),
小米: Mock.Random.float(100, 8000, 0, 0)
})
)
}
return {
code: 20000,
data: {
// 饼图
videoData: [
{
name: '小米',
value: 2999
},
{
name: '苹果',
value: 5999
},
{
name: 'vivo',
value: 1500
},
{
name: 'oppo',
value: 1999
},
{
name: '魅族',
value: 2200
},
{
name: '三星',
value: 4500
}
],
// 柱状图
userData: [
{
date: '周一',
new: 5,
active: 200
},
{
date: '周二',
new: 10,
active: 500
},
{
date: '周三',
new: 12,
active: 550
},
{
date: '周四',
new: 60,
active: 800
},
{
date: '周五',
new: 65,
active: 550
},
{
date: '周六',
new: 53,
active: 770
},
{
date: '周日',
new: 33,
active: 170
}
],
// 折线图
orderData: {
date: ['20191001', '20191002', '20191003', '20191004', '20191005', '20191006', '20191007'],
data: List
},
tableData: [
{
name: 'oppo',
todayBuy: 500,
monthBuy: 3500,
totalBuy: 22000
},
{
name: 'vivo',
todayBuy: 300,
monthBuy: 2200,
totalBuy: 24000
},
{
name: '苹果',
todayBuy: 800,
monthBuy: 4500,
totalBuy: 65000
},
{
name: '小米',
todayBuy: 1200,
monthBuy: 6500,
totalBuy: 45000
},
{
name: '三星',
todayBuy: 300,
monthBuy: 2000,
totalBuy: 34000
},
{
name: '魅族',
todayBuy: 350,
monthBuy: 3000,
totalBuy: 22000
}
]
}
}
}
}
将mock里面的第三个参数拦截后的请求逻辑进行一下替换
import Mock from 'mockjs'
// 引入mock
import homeApiData from './mockServeData/home'
//引入我们处理好的数据,作为进行拦截后的请求逻辑的数据
// 定义mock接口请求拦截
/\*\*
\* Mock.mock参数
\* 第一个是拦截接口的地址
\* 第二个是接口请求类型(可省略)
\* 第三个是一个函数=>拦截后的请求逻辑
\*/
Mock.mock('/api/home/getData','get',homeApiData.getStatisticalData)
效果
7、通用管理后台(首页可视化图表样式调整)
在前面我们已经模拟了后端以及axios封装和接口的封装和调用,调用后也获取到了数据
接下来我们就把之前的数据全部换成我们的动态数据!
7.1、首页table由静态数据切换成动态数据**
Home.vue
将获取res.data.data.tableData是返回的table数据给tableData重新赋值,这样表格就变成了动态数据
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>-->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16">
<!-- 右侧区域 -->
<div class="num">
<el-card :body-style="{display:'flex',padding:0}" v-for="item in countData" :key="item.name">
<i :style="{background:item.color}" class="icon" :class="`el-icon-${item.icon}`"></i>
<div class="detail">
<p class="dataPrice">{{ item.value }}</p>
<p class="dataDesc">{{ item.name }}</p>
</div>
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
import {getData} from '../api'
// 引入封装好的请求方法
export default {
data() {
return {
// tableData表格数据
tableData: [
],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: "技术栈",
todayBuy: "今日学习人数",
monthBuy: "本月学习人数",
totalBuy: "学习总数据"
},
// countData 学习数据统计
countData: [
{
name: "今日学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "今日收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "今日查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
},
{
name: "本月学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "本月收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "本月查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
}
]
};
},
mounted(){
// mounted挂载
getData().then(res=>{
// 获取res.data.data.tableData是返回的table数据
this.tableData=res.data.data.tableData
console.log(this.tableData)
})
}
};
</script>
<style lang="less" scoped>
.user {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img {
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail {
// 用户详情信息
.name {
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access {
// 角色
color: #999;
}
}
}
.user-info {
// 登录时间和地点
p {
line-height: 28px;
font-size: 14px;
color: #999;
span {
color: #666;
margin-left: 60px;
}
}
}
// 右侧学习数据
.num {
display: flex;
flex-wrap: wrap; // 强制换行
justify-content: space-between;
.icon {
// 图表
width: 80px;
height: 80px;
font-size: 30px;
text-align: center;
line-height: 80px;
color: white;
}
.detail{
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 15px;
.dataPrice{
font-size: 30px;
margin-bottom: 10px;
line-height: 30px;
height: 30px;
}
.dataDesc{
color: #999;
font-size: 14px;
text-align: center;
}
}
.el-card{
// 右侧卡片
width: 32%;
margin-bottom: 20px;
}
}
</style>
效果
7.2、样式完善和图标表区域布局
左侧区域和右侧区域el-col加上一个padding值
<el-col :span="8" style="padding-right:10px">
//左侧的col
<el-col :span="16" style="padding-left:10px">
//右侧的col
图表区域布局
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8" style="padding-right:10px">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>-->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16" style="padding-left:10px">
<!-- 右侧区域 -->
<div class="num">
<el-card :body-style="{display:'flex',padding:0}" v-for="item in countData" :key="item.name">
<i :style="{background:item.color}" class="icon" :class="`el-icon-${item.icon}`"></i>
<div class="detail">
<p class="dataPrice">{{ item.value }}</p>
<p class="dataDesc">{{ item.name }}</p>
</div>
</el-card>
</div>
<el-card style="height:280px">
<!-- 折线图 -->
</el-card>
<div class="tbStyle">
<el-card style="height:260px;width:48%;">
<!-- 柱状图 -->
</el-card>
<el-card style="height:260px;width:48%;">
<!-- 饼图 -->
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
import {getData} from '../api'
// 引入封装好的请求方法
export default {
data() {
return {
// tableData表格数据
tableData: [
],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: "技术栈",
todayBuy: "今日学习人数",
monthBuy: "本月学习人数",
totalBuy: "学习总数据"
},
// countData 学习数据统计
countData: [
{
name: "今日学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "今日收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "今日查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
},
{
name: "本月学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "本月收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "本月查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
}
]
};
},
mounted(){
// mounted挂载
getData().then(res=>{
// 获取res.data.data.tableData是返回的table数据
this.tableData=res.data.data.tableData
console.log(this.tableData)
})
}
};
</script>
<style lang="less" scoped>
.user {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img {
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail {
// 用户详情信息
.name {
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access {
// 角色
color: #999;
}
}
}
.user-info {
// 登录时间和地点
p {
line-height: 28px;
font-size: 14px;
color: #999;
span {
color: #666;
margin-left: 60px;
}
}
}
// 右侧学习数据
.num {
display: flex;
flex-wrap: wrap; // 强制换行
justify-content: space-between;
.icon {
// 图表
width: 80px;
height: 80px;
font-size: 30px;
text-align: center;
line-height: 80px;
color: white;
}
.detail{
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 15px;
.dataPrice{
font-size: 30px;
margin-bottom: 10px;
line-height: 30px;
height: 30px;
}
.dataDesc{
color: #999;
font-size: 14px;
text-align: center;
}
}
.el-card{
// 右侧卡片
width: 32%;
margin-bottom: 20px;
}
}
.tbStyle{
// 底部图表容器样式
margin-top: 20px;
display: flex;
justify-content: space-between;
}
</style>
图表区域效果
7.2.1、Echarts
Echarts图表官网
安装
npm i echarts@5.1.2
在项目文件夹下进行安装
安装完成后,接下来就在项目中使用把
7.2.1、折线图部分完善
上面已经对表格区域进行了一些简单的布局,接下来就是对空白区域进行一下图表的补充
Home.vue
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8" style="padding-right:10px">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>-->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16" style="padding-left:10px">
<!-- 右侧区域 -->
<div class="num">
<el-card
:body-style="{display:'flex',padding:0}"
v-for="item in countData"
:key="item.name"
>
<i :style="{background:item.color}" class="icon" :class="`el-icon-${item.icon}`"></i>
<div class="detail">
<p class="dataPrice">{{ item.value }}</p>
<p class="dataDesc">{{ item.name }}</p>
</div>
</el-card>
</div>
<el-card style="height:280px">
<!-- 折线图 -->
<div ref="echartszx" style="height:280px"></div>
</el-card>
<div class="tbStyle">
<el-card style="height:260px;width:48%;">
<!-- 柱状图 -->
</el-card>
<el-card style="height:260px;width:48%;">
<!-- 饼图 -->
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
import { getData } from "../api";
// 引入封装好的请求方法
import \* as echarts from "echarts";
// 引入echarts
export default {
data() {
return {
// tableData表格数据
tableData: [],
// orderData折线图数据
orderData: [],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: "技术栈",
todayBuy: "今日学习人数",
monthBuy: "本月学习人数",
totalBuy: "学习总数据"
},
// countData 学习数据统计
countData: [
{
name: "今日学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "今日收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "今日查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
},
{
name: "本月学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "本月收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "本月查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
}
]
};
},
mounted() {
// mounted挂载
getData().then(res => {
// 获取res.data.data.tableData是返回的table数据
this.tableData = res.data.data.tableData;
// 图表数据
console.log(this.tableData);
this.orderData = res.data.data.orderData;
// orderData折线图数据
// 基于准备好的dom,初始化echarts实例
// 获取dom元素,然后初始化echarts
const echartszx = echarts.init(this.$refs.echartszx);
// 指定图表的配置和数据
let zxOption = {};
// 处理xAxis x轴数据
const xAxis = Object.keys(this.orderData.data[0]);
const xAxisData = {
data: xAxis
};
// x轴
zxOption.xAxis = xAxisData;
// y轴
zxOption.yAxis = {};
// 图例
zxOption.legend = xAxisData;
// y轴对应数据
zxOption.series = [];
xAxis.forEach(key => {
zxOption.series.push({
name: key,
data: this.orderData.data.map(item => item[key]),
type: "line"
});
});
console.log(zxOption);
// 使用刚指定的配置项和数据显示图表。
echartszx.setOption(zxOption);
});
}
};
</script>
<style lang="less" scoped>
.user {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img {
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail {
// 用户详情信息
.name {
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access {
// 角色
color: #999;
}
}
}
.user-info {
// 登录时间和地点
p {
line-height: 28px;
font-size: 14px;
color: #999;
span {
color: #666;
margin-left: 60px;
}
}
}
// 右侧学习数据
.num {
display: flex;
flex-wrap: wrap; // 强制换行
justify-content: space-between;
.icon {
// 图表
width: 80px;
height: 80px;
font-size: 30px;
text-align: center;
line-height: 80px;
color: white;
}
.detail {
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 15px;
.dataPrice {
font-size: 30px;
margin-bottom: 10px;
line-height: 30px;
height: 30px;
}
.dataDesc {
color: #999;
font-size: 14px;
text-align: center;
}
}
.el-card {
// 右侧卡片
width: 32%;
margin-bottom: 20px;
}
}
.tbStyle {
// 底部图表容器样式
margin-top: 20px;
display: flex;
justify-content: space-between;
}
</style>
效果
7.2.2、柱状图部分完善
接下来完成我们主页左下角柱状图部分
Home.vue
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8" style="padding-right:10px">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>-->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16" style="padding-left:10px">
<!-- 右侧区域 -->
<div class="num">
<el-card
:body-style="{display:'flex',padding:0}"
v-for="item in countData"
:key="item.name"
>
<i :style="{background:item.color}" class="icon" :class="`el-icon-${item.icon}`"></i>
<div class="detail">
<p class="dataPrice">{{ item.value }}</p>
<p class="dataDesc">{{ item.name }}</p>
</div>
</el-card>
</div>
<el-card style="height:280px">
<!-- 折线图 -->
<div ref="echartszx" style="height:280px"></div>
</el-card>
<div class="tbStyle">
<el-card style="height:260px;width:48%;">
<!-- 柱状图 -->
<div ref="echartszzt" style="height:260px;"></div>
</el-card>
<el-card style="height:260px;width:48%;">
<!-- 饼图 -->
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
import { getData } from "../api";
// 引入封装好的请求方法
import \* as echarts from "echarts";
// 引入echarts
export default {
data() {
return {
// tableData表格数据
tableData: [],
// orderData折线图数据
orderData: [],
// userData用户数据
userData:[],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: "技术栈",
todayBuy: "今日学习人数",
monthBuy: "本月学习人数",
totalBuy: "学习总数据"
},
// countData 学习数据统计
countData: [
{
name: "今日学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "今日收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "今日查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
},
{
name: "本月学习数据",
value: 1234,
icon: "s-data",
color: "deeppink"
},
{
name: "本月收藏文章",
value: 210,
icon: "star-on",
color: "red"
},
{
name: "本月查看数据",
value: 1234,
icon: "thumb",
color: "chartreuse"
}
]
};
},
mounted() {
// mounted挂载
getData().then(res => {
// 获取res.data.data.tableData是返回的table数据
this.tableData = res.data.data.tableData;
// 图表数据
console.log(this.tableData);
this.orderData = res.data.data.orderData;
// orderData折线图数据
this.userData=res.data.data.userData
// 基于准备好的dom,初始化echarts实例
// 获取dom元素,然后初始化echarts
const echartszx = echarts.init(this.$refs.echartszx);
// 指定图表的配置和数据
let zxOption = {};
// 处理xAxis x轴数据
const xAxis = Object.keys(this.orderData.data[0]);
const xAxisData = {
data: xAxis
};
// x轴
zxOption.xAxis = xAxisData;
// y轴
zxOption.yAxis = {};
// 图例
zxOption.legend = xAxisData;
// y轴对应数据
zxOption.series = [];
xAxis.forEach(key => {
zxOption.series.push({
name: key,
data: this.orderData.data.map(item => item[key]),
type: "line"
});
});
console.log(zxOption);
// 使用刚指定的配置项和数据显示图表。
echartszx.setOption(zxOption);
// 柱状图
const echartszzt = echarts.init(this.$refs.echartszzt);
// 柱状图配置
let zztOption = {
legend: {
// 图例文字颜色
textStyle: {
color: "#333"
}
},
grid: {
left: "20%"
},
// 提示框
tooltip: {
trigger: "axis"
},
xAxis: {
type: "category", // 类目轴
data: this.userData.map(item=>item.date),
axisLine: {
lineStyle: {
color: "#17b3a3"
}
},
axisLabel: {
interval: 0,
color: "#333"
}
},
yAxis: [
{
type: "value",
axisLine: {
lineStyle: {
color: "#17b3a3"
}
}
}
],
color: ["#2ec7c9", "#b6a2de"],
series: [
{
name:'阅读新增用户',
data:this.userData.map(item=>item.new),
type:'bar'
},
{
name:'阅读活跃用户',
data:this.userData.map(item=>item.active),
type:'bar'
}
]
};
echartszzt.setOption(zztOption)
});
}
};
</script>
<style lang="less" scoped>
.user {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
padding-bottom: 20px;
margin-bottom: 20px;
img {
margin-right: 40px;
width: 150px;
height: 150px;
border-radius: 50%;
}
.userDetail {
// 用户详情信息
.name {
// 用户名
font-size: 32px;
margin-bottom: 10px;
}
.access {
// 角色
color: #999;
}
}
}
.user-info {
// 登录时间和地点
p {
line-height: 28px;
font-size: 14px;
color: #999;
span {
color: #666;
margin-left: 60px;
}
}
}
// 右侧学习数据
.num {
display: flex;
flex-wrap: wrap; // 强制换行
justify-content: space-between;
.icon {
// 图表
width: 80px;
height: 80px;
font-size: 30px;
text-align: center;
line-height: 80px;
color: white;
}
.detail {
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 15px;
.dataPrice {
font-size: 30px;
margin-bottom: 10px;
line-height: 30px;
height: 30px;
}
.dataDesc {
color: #999;
font-size: 14px;
text-align: center;
}
}
.el-card {
// 右侧卡片
width: 32%;
margin-bottom: 20px;
}
}
.tbStyle {
// 底部图表容器样式
margin-top: 20px;
display: flex;
justify-content: space-between;
}
</style>
效果
7.2.3、饼图部分完善
接下来完成图表的最后一部分饼状图,相对于折线图和柱状图来说简单一些。
Home.vue
<template>
<el-row>
<!-- span是所占的比例 -->
<el-col :span="8" style="padding-right:10px">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>-->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16" style="padding-left:10px">
<!-- 右侧区域 -->
<div class="num">
<el-card
:body-style="{display:'flex',padding:0}"
v-for="item in countData"
:key="item.name"
>
<i :style="{background:item.color}" class="icon" :class="`el-icon-${item.icon}`"></i>
<div class="detail">
<p class="dataPrice">{{ item.value }}</p>
<p class="dataDesc">{{ item.name }}</p>
</div>
</el-card>
</div>
<el-card style="height:280px">
<!-- 折线图 -->
<div ref="echartszx" style="height:280px"></div>
</el-card>
<div class="tbStyle">
<el-card style="height:260px;width:48%;">
<!-- 柱状图 -->
<div ref="echartszzt" style="height:260px;"></div>
</el-card>
<el-card style="height:260px;width:48%;">
<!-- 饼图 -->
<div ref="echartsbt" style="height:250px;"></div>
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
import { getData } from "../api";
// 引入封装好的请求方法
import \* as echarts from "echarts";
// 引入echarts
export default {
data() {
return {
// tableData表格数据
tableData: [],
// orderData折线图数据
orderData: [],
// userData用户数据
userData: [],
// videoData视频数据
videoData: [],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: "技术栈",
todayBuy: "今日学习人数",
monthBuy: "本月学习人数",
totalBuy: "学习总数据"
### 最后:
总结来说,面试成功=基础知识+项目经验+表达技巧+运气。我们无法控制运气,但是我们可以在别的地方花更多时间,每个环节都提前做好准备。
面试一方面是为了找到工作,升职加薪,另一方面也是对于自我能力的考察。能够面试成功不仅仅是来自面试前的临时抱佛脚,更重要的是在平时学习和工作中不断积累和坚持,把每个知识点、每一次项目开发、每次遇到的难点知识,做好积累,实践和总结。
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
![](https://img-blog.csdnimg.cn/img_convert/498b96172460fd4af1f0e5dea00d68f1.webp?x-oss-process=image/format,png)
px">
<el-card class="box-card">
<div class="user">
<!-- 用户信息 -->
<img src="../assets/tx.png" alt />
<div class="userDetail">
<p class="name">前端初见</p>
<p class="access">管理员</p>
</div>
</div>
<div class="user-info">
<p>
上次登录时间:
<span>2023-3-29</span>
</p>
<p>
上次登录地点:
<span>中山</span>
</p>
</div>
</el-card>
<el-card style="margin-top: 20px; height:380px" class="box-card">
<!-- 静态 -->
<!-- <el-table :data="tableData" style="width: 100%">
<el-table-column prop="name" label="技术栈"></el-table-column>
<el-table-column prop="todayBuy" label="今日学习人数" ></el-table-column>
<el-table-column prop="monthBuy" label="本月学习人数"></el-table-column>
<el-table-column prop="totalBuy" label="学习总数据"></el-table-column>
</el-table>-->
<!-- 遍历生成表格 -->
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val" />
</el-table>
</el-card>
</el-col>
<el-col :span="16" style="padding-left:10px">
<!-- 右侧区域 -->
<div class="num">
<el-card
:body-style="{display:'flex',padding:0}"
v-for="item in countData"
:key="item.name"
>
<i :style="{background:item.color}" class="icon" :class="`el-icon-${item.icon}`"></i>
<div class="detail">
<p class="dataPrice">{{ item.value }}</p>
<p class="dataDesc">{{ item.name }}</p>
</div>
</el-card>
</div>
<el-card style="height:280px">
<!-- 折线图 -->
<div ref="echartszx" style="height:280px"></div>
</el-card>
<div class="tbStyle">
<el-card style="height:260px;width:48%;">
<!-- 柱状图 -->
<div ref="echartszzt" style="height:260px;"></div>
</el-card>
<el-card style="height:260px;width:48%;">
<!-- 饼图 -->
<div ref="echartsbt" style="height:250px;"></div>
</el-card>
</div>
</el-col>
</el-row>
</template>
<script>
import { getData } from "../api";
// 引入封装好的请求方法
import \* as echarts from "echarts";
// 引入echarts
export default {
data() {
return {
// tableData表格数据
tableData: [],
// orderData折线图数据
orderData: [],
// userData用户数据
userData: [],
// videoData视频数据
videoData: [],
// tableLabel根据表格整理表格表格label数据
tableLabel: {
name: "技术栈",
todayBuy: "今日学习人数",
monthBuy: "本月学习人数",
totalBuy: "学习总数据"
### 最后:
总结来说,面试成功=基础知识+项目经验+表达技巧+运气。我们无法控制运气,但是我们可以在别的地方花更多时间,每个环节都提前做好准备。
面试一方面是为了找到工作,升职加薪,另一方面也是对于自我能力的考察。能够面试成功不仅仅是来自面试前的临时抱佛脚,更重要的是在平时学习和工作中不断积累和坚持,把每个知识点、每一次项目开发、每次遇到的难点知识,做好积累,实践和总结。
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)**
[外链图片转存中...(img-iGTjg2w6-1715661267614)]