登录nodejs.cn下载,配置环境变量,配置过程,配置过程2
打开npmmirror.com,在终端运行下面代码
npm install -g cnpm --registry=https://registry.npmmirror.com
运行完成后,输入cnpm -v检验是否安装成功,若cnpm -v无法加载
安装yarn,并检验是否安装成功
vue-cli官方文档
cnpm install -g @vue/cli
检验脚手架是否安装成功,vue -V
vue create vue-manage
选择[Vue 2] babel, eslint,用yarn安装
运行vue run serve
npm i element-ui -S
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
将elementui注入vue,在main.js中写入
Vue.use(ElementUI)
npm run build
npm install babel-plugin-component -D
//借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
首先,安装 babel-plugin-component
改写mian.js中import ElementUI from 'element-ui';为import {Button} from 'element-ui';
改写Vue.use(ElementUI)为Vue.use(Button)
在babel.config.js中写入
npm i @babel/preset-env -D
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
// ["@babel/preset-env", { "modules": false }] //有问题
],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
vue-router官方文档
npm i [email protected]
new Vue({
router,
render: h => h(App),
}).$mount('#app')
import router from './router'
//import router from '../router'
import Vue from 'vue'
import VueRouter from 'vue-router'
解决报错:Home报错
我是Home
Vue.use(VueRouter)//vuerouter全局引入
import Home from '../views/Home.vue'
import User from '../views/User.vue'
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import User from '../views/User.vue'
Vue.use(VueRouter)//vuerouter全局引入
//1.创建路由组件
//2.将路由与组件进行映射
const routes = [
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
]
const router = new VueRouter({
mode:'history',//路由匹配模式
routes
})
//配置router
export default router
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import User from '../views/User.vue'
Vue.use(VueRouter)//vuerouter全局引入
//1.创建路由组件
//2.将路由与组件进行映射
const routes = [
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
]
//3.创建router实例
const router = new VueRouter({
// mode:'history',//路由匹配模式
routes
})
//配置router
export default router
export default 是什么
关闭eslint校验:
在views中新建Main.vue主页面,并在index.js中引入
main
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import User from '../views/User.vue'
import Main from '../views/Main.vue'
const routes = [
//主路由
{
path:'/',
component:Main,
children:[
//子路由
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
]
},
]
引用element-ui的container布局(记得在main.js中引入局部element-ui组件)
安装less样式
npm i less
npm i [email protected] --legacy-peer-deps
Main.vue页面
Aside
Header
引入element-ui的NavMenu导航菜单,到component中新建CommonAside.vue(侧边栏组件)
在主页Main.vue中引入CommonAside组件
CommonAside组件中实现可展开
return {
isCollapse: false
};
将导航二移到顶部,删除导航三、四
只保留导航二、导航一和导航一下面的选项一
对内容进行渲染,在data的return下加入数据
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'
}
]
}
],
过滤数据
computed:{
//没有子菜单
noChildren() {
return this.menuData.filter(item => !item.children)
},
//有子菜单
hasChildren() {
return this.menuData.filter(item => item.children)
}
}
引入icon图标
{{item.label}}
noChildren效果图:
{{item.label}}
{{subItem.label}}
安装less,less-loader
npm i [email protected]
npm i [email protected]
在component文件下的CommonAside.vue中
引入less部分
通用后台管理系统
{{item.label}}
{{item.label}}
{{subItem.label}}
去白边:在App.vue中的style标签
更改
在CommonAside.vue中style的h3中
h3{
color: #fff;
text-align: center;
line-height: 48px;
font-size: 16px;
font-weight: 400;
}
在App.vue中的style的html,body中
html,body,h3{
margin: 0;
padding: 0
}
在views中新建Mall.vue,PageOne.vue,PageTwo.vue
在router的index.js中引入
import Mall from '../views/Mall.vue'
import PageOne from '../views/PageOne.vue'
import PageTwo from '../views/PageTwo.vue'
const routes = [
//主路由
{
path:'/',
component:Main,
children:[
//子路由
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
{path: '/mall',component:Mall},//商品管理
{path: '/page1',component:PageOne},//页面1
{path: '/page2',component:PageTwo},//页面2
]
},
]
实现点击跳转:
添加@click事件
{{item.label}}
在methods中加入click事件
//点击菜单
clickMenu(item){
console.log(item)
this.$router.push(item.path)
}
由于在main.js中挂载了router到vue实例上,所以可以使用$router属性,然后调用本身的push方法
存在问题:
点击首页跳转的是 ‘/’ ,原因是在当前路径再点击跳转当前路径会报错
解决:
在route的index.js中,加入重定向,意思是当路径是‘/’的时候重定向到‘/home’
const routes = [
//主路由
{
path:'/',
component:Main,
redirect:'/home',//重定向
children:[
//子路由
{path: '/home',component:Home},//首页
{path: '/user',component:User},//用户管理
{path: '/mall',component:Mall},//商品管理
{path: '/page1',component:PageOne},//页面1
{path: '/page2',component:PageTwo},//页面2
]
},
]
二级菜单的跳转:
{{item.label}}
{{subItem.label}}
解决重复点击报错问题:
//点击菜单
clickMenu(item){
console.log(item)
//当页面路由与跳转的路由不一致才允许跳转
if(this.$route.path !== item.path && !(this.$route.path === '/home' && (item.path
=== '/')))
{this.$router.push(item.path)}
//$route表示当前页面路由,$router表示整个router实例
}
点击首页三次
在component里新建CommonHeader.vue
在Main.vue中引入CommonHeader.vue组件
去掉padding
在Main.vue中加入
引入element-ui的icon
在CommonHeader.vue中
面包屑
首页
引入element-ui的dropdown组件
个人中心
退出
首页
个人中心
退出
在 .header-container 中写入样式
.r-content{
.user{
width:40px;
height:40px;
border-radius:50%;
}
}
vuex是什么
npm i [email protected]
在src下新建文件夹store,store下新建index.js,tab.js(管理菜单相关数据),
之前的isCollapse定义在字段内部(return)下
index.js中
import Vue from 'vue'
import Vuex from 'vuex'
import tab from './tab'
Vue.use(Vuex)
//创建vuex的实例,并对外暴露
export default new Vuex.Store(
{
modules:{
tab
}
}
)
tab.js中
export default {
state:{
isCollapse:false //控制菜单的展开还是收起
},
mutations: {
//修改菜单展开收起的方法
collapseMenu(state) {
state.isCollapse = !state.isCollapse
}
}
}
store实例挂载到vue实例中,需要在main.js中引入
import store from './store'
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
第一步,在CommonHeader.vue中获取mutations方法
通过commit方法调用对应的mutations
第二步,在CommonAside.vue中获取store
在computed属性下写入(删除之前定义在data中的isCollapse)
isCollapse() {
return this.$store.state.tab.isCollapse
}
在CommonAside.vue中
{{isCollapse ? '后台': '通用后台管理系统' }}
在Main.vue中,将width="200px"改为auto
去掉缝隙,在 CommonAside.vue中,加入style
使用layout布局
使用card卡片,实现阴影效果
在Home.vue中,使用layout布局并加入一个card
Admin
超级管理员
上次登陆时间:2021-7-19
上次登陆地点:武汉
在Home.vue中第二个
并在return中写入
tableData: [
{
name: 'oppo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: 'vivo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '苹果',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '小米',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '三星',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '魅族',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
]
在return中写入tableLabel
export default {
data(){
return{
tableData: [
{
name: 'oppo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: 'vivo',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '苹果',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '小米',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '三星',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
},
{
name: '魅族',
todayBuy: 100,
monthBuy: 300,
totalBuy: 800
}
],
tableLabel:{
name: '课程',
todayBuy: '今日购买',
monthBuy: '本月购买',
totalBuy: '总购买',
}
}
}
}
注释掉之前的 用v-for动态循环遍历tableLabel
使用icon图标
{{ item.value }}
{{ item.name }}
.num{
.icon{
width:80px;
height:80px;
font-size:30px;
text-align:center;
line-height:80px;
color:#fff;
}
}
.detail{
display:flex;
flex-direction:column;
justify-content: center;
}
.detail{
margin-left: 15px;
display:flex;
flex-direction:column;
justify-content: center;
.price{
font-size: 30px;
margin-bottom: 10px;
line-height: 30px;
height: 30px;
}
.desc{
font-size: 14px;
color: #999;
text-align: center;
}
}
display:flex
.el-card{
width:32%;
margin-bottom: 20px;
}
调整边距:
axios文档
npm install axios
在src下新建文件夹utils中新建文件request.js
import axios from 'axios'
const http = axios.create({
//通用请求地址前缀
baseURL:'/api',
timeout:10000,//超时时间
})
export default http
添加拦截器:
import axios from 'axios'
const http = axios.create({
//通用请求地址前缀
baseURL:'/api',
timeout:10000,//超时时间
})
// 添加请求拦截器,绑定http实例
http.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器,绑定http实例
http.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
export default http
在src下新建文件夹api中新建index.js
import http from '../utils/request'
//请求首页数据
export const getData = () => {
//返回一个promise对象
return http.get('/home/getData')
}
调用接口:
在Home.vue中
调用成功
mock文档,用来前端模拟后端接口
# 安装
npm install mockjs
在api下新建mock.js
import Mock from 'mockjs'
//定义mock请求拦截
Mock.mock('/api/home/getData',function(){
//拦截到请求后的处理逻辑
console.log('拦截到了')
})
在main.js中引入
import './api/mock'
拦截到了
在mock中return 1
在api下新建文件夹mockServeData,中新建home.js和permission.js
在home.js中写入
// 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.js中调用
import Mock from 'mockjs'
import homeApi from './mockServeData/home'
//定义mock请求拦截
Mock.mock('/api/home/getData', homeApi.getStatisticalData)
解构赋值运用到函数参数
在Home.vue中
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(tableData)
})
}
打印成功
删除tableData中写死的数据
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
this.tableData = tableData
})
}
左右各加10px
.graph{
margin-top: 20px;
display: flex;
justify-content: space-between;
.el-card{
width:48%;
}
}
npm i [email protected]
在Home.vue中引入echarts
import * as echarts from 'echarts'
初始化echarts实例
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var option = {}
//处理数据xAxis
const { orderData } = data.data
const xAxis = Object.keys(orderData.data[0])
console.log(xAxis)
})
}
打印x轴数据
处理数据:
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData } = data.data
const xAxis = Object.keys(orderData.data[0])
echarts1Option.xAxis = xAxis
echarts1Option.legend = {
data:xAxis
}
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
})
console.log(xAxis)
})
}
显示折线图
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData } = data.data
const xAxis = Object.keys(orderData.data[0])
const xAxisData = {
data:xAxis
}
echarts1Option.xAxis = xAxisData
echarts1Option.yAxis = {}
echarts1Option.legend = xAxisData
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
// 使用刚指定的配置项和数据显示图表。
echarts1.setOption(echarts1Option)
})
console.log(xAxis)
})
}
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData,userData } = data.data
const xAxis = Object.keys(orderData.data[0])
const xAxisData = {
data:xAxis
}
echarts1Option.xAxis = xAxisData
echarts1Option.yAxis = {}
echarts1Option.legend = xAxisData
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
// 使用刚指定的配置项和数据显示图表。
echarts1.setOption(echarts1Option)
//柱状图
// 基于准备好的dom,初始化echarts实例
const echarts2 = echarts.init(this.$refs.echarts2)
// 指定图表的配置项和数据
const echarts2Option = {
legend: {
// 图例文字颜色
textStyle: {
color: "#333",
},
},
grid: {
left: "20%",
},
// 提示框
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category", // 类目轴
data: 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:userData.map(item =>item.new),
type:'bar'
},
{
name:'活跃用户',
data:userData.map(item =>item.active),
type:'bar'
}
],
}
echarts2.setOption(echarts2Option)
})
})
}
mounted(){
getData().then(({data}) => {
const { tableData } = data.data
console.log(data)
this.tableData = tableData
// 基于准备好的dom,初始化echarts实例
const echarts1 = echarts.init(this.$refs.echarts1)
// 指定图表的配置项和数据
var echarts1Option = {}
//处理数据xAxis
const { orderData,userData,videoData } = data.data
const xAxis = Object.keys(orderData.data[0])
const xAxisData = {
data:xAxis
}
echarts1Option.xAxis = xAxisData
echarts1Option.yAxis = {}
echarts1Option.legend = xAxisData
echarts1Option.series = []
xAxis.forEach(key => {
echarts1Option.series.push({
name:key,
data:orderData.data.map(item => item[key]),
type:'line'
})
console.log(echarts1Option)
// 使用刚指定的配置项和数据显示图表。
echarts1.setOption(echarts1Option)
//柱状图
// 基于准备好的dom,初始化echarts实例
const echarts2 = echarts.init(this.$refs.echarts2)
// 指定图表的配置项和数据
const echarts2Option = {
legend: {
// 图例文字颜色
textStyle: {
color: "#333",
},
},
grid: {
left: "20%",
},
// 提示框
tooltip: {
trigger: "axis",
},
xAxis: {
type: "category", // 类目轴
data: 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:userData.map(item =>item.new),
type:'bar'
},
{
name:'活跃用户',
data:userData.map(item =>item.active),
type:'bar'
}
],
}
echarts2.setOption(echarts2Option)
//饼状图
// 基于准备好的dom,初始化echarts实例
const echarts3 = echarts.init(this.$refs.echarts3)
// 指定图表的配置项和数据
const echarts3Option = {
tooltip: {
trigger: "item",
},
color: [
"#0f78f4",
"#dd536b",
"#9462e5",
"#a6a6a6",
"#e1bb22",
"#39c362",
"#3ed1cf",
],
series: [
{
data:videoData,
type:'pie'
}
],
}
echarts3.setOption(echarts3Option)
})
})
}
在components中的CommonHeader.vue中,引入面包屑
首页
活动管理
活动列表
活动详情
定义数据部分:
在store的tab.js中
state:{
isCollapse:false ,//控制菜单的展开还是收起
tabsList: [
{
path: '/',
name: 'home',
label: '首页',
icon: 's-home',
url: 'Home/Home'
}
]//面包屑的数据
},
mutations: {
//修改菜单展开收起的方法
collapseMenu(state) {
state.isCollapse = !state.isCollapse
},
//更新面包屑数据
selectMenu(state,val){
console.log(val,'val')
}
}
在CommonAside中,调用mutations
更新数据:
在tab.js中
mutations: {
//修改菜单展开收起的方法
collapseMenu(state) {
state.isCollapse = !state.isCollapse
},
//更新面包屑数据
selectMenu(state,val){
console.log(val,'val')
//判断添加的数据是否为首页
if(val.name !== 'home'){
const index = state.tabsList.findIndex(item => item.name === val.name)
//如果不存在
if(index === -1){
state.tabsList.push(val)
}
}
}
}
使用:
在CommonHeader.vue中
{{item.label}}
添加样式在CommonHeader中:
.l-content {
display: flex;
align-items: center;
/deep/.el-breadcrumb__item{
.el-breadcrumb__inner {
font-weight:normal;
&.is-link {
color:#666
}
}
&:last-child {
.el-breadcrumb__inner{
color: #fff;
}
}
}
}
在components中新建CommonTag.vue
{{ item.label }}
在Main.vue中引入CommonTag.vue
在router中的index.js中加入‘name’
点击tag跳转:
methods:{
//点击tag跳转的功能
changeMenu(item){
// console.log(item)
this.$router.push({name:item.name})
}
}
点击删除:
methods:{
...mapMutations(['closeTag']),
//点击tag跳转的功能
changeMenu(item){
// console.log(item)
this.$router.push({name:item.name})
},
//点击tag删除的功能
handleClose(item,index){
//调用store中的mutations
this.closeTag(item)
const length = this.tags.length - 1
}
}
在tab.js中
点×有数据
只删除(还未跳转):
//删除指定的tag数据
closeTag(state,item){
// console.log(item,'item')
const index = state.tabsList.findIndex(val => val.name === item.name)
state.tabsList.splice(index,1)
}
删除并跳转:
在CommonTag.vue中
//点击tag删除的功能
handleClose(item,index){
//调用store中的mutations
this.closeTag(item)
const length = this.tags.length
//删除之后的跳转
if (item.name !== this.$route.name) {
return
}
//表示的是删除的最后一项
if(index === length) {
this.$router.push({
name:this.tags[index - 1].name
})
}
else{
this.$router.push({
name:this.tags[index].name
})
}
}
添加样式
删除最后一个:
删除中间: