2024年最全vue通用后台管理系统(保姆级)--持续更新中_vue管理后台(1),吊打面试官-前端中高级面试题

最后

由于篇幅限制,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



首页
个人中心 退出

![在这里插入图片描述](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 文档
在这里插入图片描述

Mock.js文档
在这里插入图片描述

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)]

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值