之前学习完vue做了一个后台管理项目,但是这个项目并不完整,在做的过程出现了一些bug,不过也算做的第一个项目
一、配置项目环境
1.1下载node.js
在node.js官网中直接下载,现在完成后在终端输入 node -v 可以查看node的版本
node.js下载好后npm也随之可以使用
npm -v 查看npm版本
1.2.安装yarn
npm install -g yarn
3.安装cnpm
npm install -g cnpm --registry=http://registry.npm.taobao.org
4.安装vue-cli脚手架
** npm install -g @vue/cli**
5.创建项目 vue create (名称)
然后进行一些配置
**5.引入element ui **
npm i element-ui -S
如果引入element ui 出现卡住不动 可以删除node包 从新npm i 引入element ui
按需引入element ui 参考官方文档
借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
element ui 的使用
在Main主页进行布局 引入element ui 中的布局容器
<template>
<div>
<el-container>
<el-aside width="auto">
<CommonAside></CommonAside>
</el-aside>
<el-container style="height:100%">
<el-header>Header</el-header>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</template>
注意: 每一次引入一个新的ui样式 需要按需引入 在main.js中进行绑定
6.vue-vuter 路由的使用
npm i vue-router@3.5.2 -S 安装路由模块
在router文件下的index中,进行配置
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../view/Home.vue'
import User from '../User/user.vue'
Vue.use(VueRouter)
const routes =[
{ path: '/home' ,component: Home},
{ path: '/user' ,component: User}
]
const router=new VueRouter({
routes,
mode:'history'
})
export default router
**7.引入less **
npm i less
**下载less 解析器 **
**注意:出现bug可能是单词没有写对 **components
二、组件化开发
8.对aside侧边栏组件进行 渲染 v-for
<template>
<div>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse" text-color="#fff">
<h1>{{ isCollapse? '后台' : '后台管理系统' }}</h1>
<el-menu-item index="2" v-for="item in nochildren" :key="item.name" @click="clickmnue(item)">
<i :class="`el-icon-${item.icon}`"></i>
<span slot="title">{{ item.label }}</span>
</el-menu-item>
<el-submenu index="1" v-for="item in haschildren" :key="item.label" text-color="#fff">
<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" >
<el-menu-item :index="subItem.path" @click="clickmnue(subItem)">{{ subItem.label }}</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</div>
</template>
<script>
export default {
name: 'CommonAside',
data () {
return {
isCollapse: false,
menu: [
{
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: '首页',
icon: 'setting',
url: 'Other/PageOne'
},
{
path: '/page2',
name: 'page2',
label: '首页',
icon: 'setting',
url: 'Other/PageTwo'
}
]
}
]
};
9.进行路由规则的配置
const routes =[
{
path:'/',
component:Main,
redirect: '/home',
children:[
{ path:'/home',component:Home }, //home首页
{ path: '/user',component:User }, //用户页面
{ path: '/mall' ,component: Mall},
{ path: '/page1',component: PageOne},
{ path: '/page2',component: PageTwo}
]
}
]
解决一个报错 就是当我重复点击同一条路由 他不会报错
if(this.$route.path !==item.path && !(this.$route.path=='/home' &&( item.path==='/'))){
this.$router.push(item.path)
}
8.由于Header部分是不变的所以,我们把Header单独做成一个组件 名为commenHeader
<template>
<div class="container">
<div class="l-container">
<el-button icon="el-icon-menu" size="mini"></el-button>
<span class="text">首页</span>
</div>
<div class="r-container">
<el-dropdown>
<span class="el-dropdown-link">
<img src="../assets/image/333965683045293120.jpg" alt="" class="user">
</span>
<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 {
}
</script>
<style lang="less" scoped>
.container {
height: 60px;
background-color: #333;
// display: flex;
// justify-content: space-between;
// align-items: center;
}
.r-container{
float: right;
margin-top:-50px ;
margin-right: 15px;
.user{
width: 40px;
height: 40px;
border-radius: 50%;
}
}
.text {
color: #fff;
font-size: 14px;
margin-left: 10px;
}
.el-dropdown-link {
cursor: pointer;
color: #409EFF;
}
.el-icon-arrow-down {
font-size: 12px;
}
</style>
9.实现左侧 折叠功能
实现折叠功能需要把header组件的值传递给aside组件,我们可以使用Event bus 方法传递,但是这种方法已经在vue3中被移除,所以我们使用其他方法来传递值
使用vuex方法
什么是vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension(opens new window),提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
引用链接https://vuex.vuejs.org/zh/
什么是“状态管理模式”?
:::info
这个状态自管理应用包含以下几个部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的简单示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux(opens new window)、Redux(opens new window)和 The Elm Architecture(opens new window)。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
如果你想交互式地学习 Vuex,可以看这个 Scrimba 上的 Vuex 课程(opens new window),它将录屏和代码试验场混合在了一起,你可以随时暂停并尝试。
引用链接https://vuex.vuejs.org/zh/ vuex官方文档
:::
安装 npm install vuex@3.6.2
配置vuex:
1.配置vuex
在main.js中引入store并且挂载在vue实例上
import store from '@/store'
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app')
2.配置store index.js
import Vue from 'vue'
import Vuex from 'vuex'
import tab from '@/store/tab'
Vue.use(Vuex)
// 创建vuex实例
export default new Vuex.Store({
modules:{
tab
}
})
export default{
state:{
isCollapse:false //控制菜单展开还是收起
},
mutations:{
// 点击事件展开折叠侧边栏
CollapseMenu(state){
state.isCollapse=!state.isCollapse
}
}
}
在组件中使用vuex方法
methods:{
changemenu()是点击事件
changemenu(){
this.$store.commit('CollapseMenu')
console.log(213);
}
}
两个小问题:1.左侧有缝隙 找到border设置none 2.折叠后字体变为两个 用插值表达式
10.对Home组件进行布局
引入element ui 中的基础布局 再引入 Card卡片
axios发送请求:
**1.下载axios ** npm install axios
2.对axios进行二次封装
为什么要对axios进行二次封装?
答:主要是要用到请求拦截器和响应拦截器;
请求拦截器:可以在发请求之前可以处理一些业务
响应拦截器:当服务器数据返回以后,可以处理一些事情
import axios from "axios";
const http=axios.create({
// 请求的地址前缀
baseURL:'api/',
// 请求超时,如果超过这个时间就不请求了
timeout:10000
})
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
export default http
然后在组件中导入api 调用里面的方法在mounted状态中发送请求
import { getDate } from '@/api/index'
mounted() {
getDate().then(function(res){
console.log(res);
})
3.mock
mock解决的问题
开发时,后端还没完成数据输出,前端只好写静态模拟数据。数据太长了,将数据写在js文件里,完成后挨个改url。某些逻辑复杂的代码,加入或去除模拟数据时得小心翼翼。想要尽可能还原真实的数据,要么编写更多代码,要么手动修改模拟数据。特殊的格式,例如IP,随机数,图片,地址,需要去收集
前端用来模拟后端接口的工具
1.mock的使用
npm i mockjs
import Mock from 'mockjs'
import Homedata from '@/api/mockServeData/home'
Mock.mock('api/home/getData','get',Homedata.getStatisticalData)
使用
import { getDate } from '@/api/index'
mounted () {
getDate().then( ({ data })=> {
console.log(data.data.tableData);
this.tableData=data.data.tableData
})
}
11.echarts的使用
1.eacharts使用方法
查看echarts官网
npm install echarts --save
项目中引入echarts
import * as echarts from ‘echarts’;
echarts官网
常用的eacharts库
echarts使用步骤
1.下载并引入echarts文件
2.准备一个具有大小的DOM容器
3.初始化echarts实例对象
4.指定配置项和数据
5.将配置项设置给echarts实例对象
// 初始化eacharts实例对象
const mycharts = echarts.init(this.$refs.echarts1)
// 准备配置项
var option={
// x轴 类目轴
xAxis: {
type:'category', 类目轴
data: ['小明','小城','晓东']
},
// y轴
yAxis: {
type:'value' 数值轴
},
series: [
{
name: '语文',
type:'bar', bar表示柱状图
data:[70,92,87]
}
]
}
// 将配置好的eacharts文件给setoption
mycharts.setOption(option)
})
对eacharts的配置项进行配置可以参考官方文档
使用eacharts设置折线图、条形图、饼桩图
</div>
<!-- 折线图 -->
<el-card style="height:230px;">
<div ref="echarts1" style="width:800px; height:230px"></div>
</el-card>
<div class="graph">
<!-- 柱状图 -->
<el-card style="height:260px">
<div ref="eacharts2" style="height:260px;"></div>
</el-card>
<!-- 饼状图 -->
<el-card style="height:260px">
<div ref="eacharts3" style="height260px"></div>
</el-card>
</div>
--------------------------------------------------------------------------
配置选项
mounted () {
getDate().then(({ data }) => {
this.tableData = data.data.tableData
// 折线图
// 1.获取DOM
const mycharts = echarts.init(this.$refs.echarts1)
const { orderData,userData,videoData } = data.data
console.log(videoData);
// 把data里面的枚举出来
const xAxis = Object.keys(orderData.data[0])
var echarts10options = {
// x轴是手机品牌
xAxis: {
type: 'category',
data: xAxis
},
yAxis: {
},
series: [],
legend: {
data: xAxis
}
}
xAxis.forEach(key => {
echarts10options.series.push({
name: key,
type: 'line',
data: orderData.data.map(item => item[key])
})
})
mycharts.setOption(echarts10options)
// 柱状图
const eacharts2 = echarts.init(this.$refs.eacharts2)
const eacharts2options = {
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'
}
],
}
eacharts2.setOption(eacharts2options)
})
// 饼状图
const eacharts3 = echarts.init(this.$refs.eacharts3)
const eacharts3options = {
tooltip: {
trigger: "item",
},
color: [
"#0f78f4",
"#dd536b",
"#9462e5",
"#a6a6a6",
"#e1bb22",
"#39c362",
"#3ed1cf",
],
series: [
{
data: videoData,
type: 'pie'
}
]
}
eacharts3.setOption(eacharts3options)
}
}
出现了一个bug 饼状图没显示
User组件用户管理模块 form组件
1.引入element-ui中的dialog弹窗
2.引入form表单
对表单中的input进行v-model双向数据绑定,然后使用element-ui提供的方法对表单进行校验,最后对表单的关闭和提交按钮进行编写 无论提交还是取消都要重置表单中的内容,提交之前还要校验用户是否填写完表单内容<br />![image.png](https://cdn.nlark.com/yuque/0/2023/png/34518336/1675588214964-1e9e27b1-c715-44f2-be4c-e23a840ffcc2.png#averageHue=%23fefefe&clientId=u56459d8e-229a-4&from=paste&height=379&id=u1612b9a7&name=image.png&originHeight=664&originWidth=1154&originalType=binary&ratio=1&rotation=0&showTitle=false&size=52953&status=done&style=none&taskId=ud23b7718-c475-404a-984f-d5250137ab3&title=&width=659.4285714285714)** 引入**element ui 中的form表单![image.png](https://cdn.nlark.com/yuque/0/2023/png/34518336/1675593161783-b1b0e535-3057-4a12-bb15-065972e5faf6.png#averageHue=%23c3c3c3&clientId=u56459d8e-229a-4&from=paste&height=472&id=ue2bbaade&name=image.png&originHeight=826&originWidth=1880&originalType=binary&ratio=1&rotation=0&showTitle=false&size=45495&status=done&style=none&taskId=u4c1bcf21-5b11-4c3e-aa90-351b1bcf109&title=&width=1074.2857142857142)<br />**对表单里面的输入进行校验**<br />对表单使用这个方法**:rules="rules" **<br />**具体参考官方文档**
prop
<el-form-item label="姓名" prop="name">
<el-input placeholder="请输入姓名" v-model="form.name"></el-input>
</el-form-item>
rules: {
name: [
{ required: true, message: '请输入活动姓名' }
],
age: [
{ required: true, message: '请输入年龄' }
],
region: [
{ required: true, message: '请选择性别' }
],
address: [
{ required: true, message: '请输入地址' }
],
date1: [
{required: true, message: '请选中出生日期'}
]
}
1.当弹窗关闭时,需要的对弹窗里面的内容重置
使用resetFileld方法
2.当提交表单时使用这个方法可以对表单进行判断
在dialog中有一个before-close的方法 相当于右上角的关闭符号点击他触发一个事件对表单进行重置
methods: {
handleClose (done) {
// 对表单进行清空
this.$refs.form.resetFields()
this.dialogVisible = false
},
submit(){
this.$refs.form.validate((valid)=>{
if(valid){
// 清空表单数据
this.$refs.form.resetFields()
this.dialogVisible=false
}
})
}
}
3.从element-ui中引入表单
使用mock假数据,获得接口
**然后在user组件中调用接口,并且把接口中的数据渲染到表单中 **
报错原因是因为this指向问题
:::info
Vue中的箭头函数与function()有什么区别呢?
我参考了这篇文章
1、this指向问题:
(1)funtion普通函数中this指向window: 所以如果需要在function函数中使用this对象,需要事先把this对象赋值给其他变量,如:
let self = this;
this.getReportId().then(function(result) {
self.id = result;
alert(self.id);
});
(2)箭头函数中this指向vue实例: 箭头函数相当于匿名函数,并且简化了函数定义。看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。 此时this在箭头函数中已经按照词法作用域绑定了。很明显,使用箭头函数之后,箭头函数指向的函数内部的this已经绑定了外部的vue实例了。如:
this.getReportId().then(result => {
this.id = result;
alert( this.id);
版权声明:本文为CSDN博主「supreluc」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45687036/article/details/123459833
:::