vue项目实战(没学完还在更)

1.3 电商后台管理系统的开发模式(前后端分离)

后端负责写接口,管理数据库
前端负责调接口(基于vue技术栈,ajax)

1.4 电商后台管理系统的技术选型

1.前端项目技术栈
  • vue
  • vue-router(路由)
  • Element-UI(前端UI组件库)
  • Axios(网络数据请求)
  • Echarts(图形化表)
2.后端项目技术栈
  • Node.js
  • Express
  • Jwt
  • Mysql
  • Sequelize

2.项目初始化

2.1前端项目初始化步骤

  • 安装vue脚手架
    • npm install webpack@3.6.0 -g
    • npm install @vue/cli -g
  • 通过vue脚手架创建项目
    • vue ui通过可视化的形式来创建vue项目【vue ui】
  • 配置vue路由
  • 配置Element-UI组件库
    • 在可视化界面中点击安装插件
  • 配置axios库(支持在开发过程中发起网络数据请求)
    • 在可视化界面中安装依赖
  • 初始化git远程仓库(用git进行源代码的管理)
  • 将本地项目托管到github或码云中
    • 设置公钥
    • 把项目git到码云中
    • 在这里插入图片描述

2.2后台项目的环境安装配置

  • 安装mysql数据库
  • 安装node.js
  • 配置项目相关信息
  • 启动项目
  • 使用postman测试后台项目接口是否正常
    • postman接口测试工具

3.登录/退出功能

3.1登录概述

  • 1.登录业务流程
    • 在登录页面输入用户名和密码
    • 调用后台接口进行验证
    • 通过验证之后,根据后台的响应状态跳转到项目主页
  • 2.登陆业务相关技术点
    • http是无状态的,但登录成功之后需要记录用户的登陆状态
    • 通过cookie在客户端记录状态
    • 通过session在服务器端记录状态
    • 通过token方式维持状态
    • 如果服务器后台接口和前端vue之间不存在跨域问题,那么就用cookie、session来维持登录状态,否则用token

3.2登录–token原理分析

在这里插入图片描述

3.3登录功能实现

  • 1.登录页面的布局
    • 通过Element-UI组件实现布局
      • el-form 表单组件
      • el-form-item 用户名,密码区域,登录,重置区域也是item项
      • el-input 文本输入框
      • el-button 按钮
      • 字体图标 两个小图标
      • 在这里插入图片描述
  • 2.创建登录页面
  • 一般开发一个新功能的时候,都要把他先写在项目的一个新分支下,当这个功能开发完成,再把它合并到主分支下
  • 在这里插入图片描述
    这是项目运行后最开始现实的原始页面,现在我们需要修改源码让它变成上面那张图那样的登录框页面项目原始页面
1.先在项目的components目录下新建一个login.vue文件(一个单文件组件),分为三个部分:模板template,行为script,样式style
  • 在这里插入图片描述
2.通过路由的形式把这个login组件渲染到app根组件中
  • 在这里插入图片描述
3.在app根组件中放一个路由的占位符
  • 在这里插入图片描述
4.开始写登录页面
  • 改login.vue
    在这里插入图片描述
  • 写一个全局样式在这里插入图片描述
  • 把全局样式文件导入到根目录下
  • 在这里插入图片描述
    • 写登录页面的小盒子
    • 在这里插入图片描述
    • css盒子垂直水平居中给方式1:平移 定位+transform,即先把盒子的左上角平移到页面中心,再用transfor以盒子自身为基准向右向上平移半个长和宽,这样就使盒子的中心在页面中间了在这里插入图片描述
5.绘制默认头像

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.绘制登录表单区域

要用Element-UI的一些组件:form表单

  • 进入Element-UI的官网直接有源码可以复制在这里插入图片描述
  • 加入element-ui的源码之后会报错,因为还没导入这里面用到的一些组件,所以需要按需导入在这里插入图片描述
  • 下面是这部分的实现代码和效果:在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
7.绘制带icon的input输入框

Element-UI
eg.

<el-input v-model="loginForm.username" prefix-icon="el-icon-user-solid"></el-input>            
  • 1导入Element-UI官方给好的图标
  • 2用v-model绑定输入的用户名数据
<el-input v-model="loginForm.password" prefix-icon="el-icon-lock" type="password"></el-input>

在这里插入图片描述

  • type设为password就可以保证输入密码时看到的是*****
8.实现表单数据验证

【表单验证】:在防止用户犯错的前提下,尽可能让用户更早地发现并纠正错误。

  • 1.给el-form通过属性绑定rules绑定一个校验规则对象:
<el-form :model="loginForm" :rules="loginFormRules" label-width="0px" class="login_form"> 
  • 2校验规则对象写在script里面的data中,在校验规则对象中定义几个校验规则的属性也可以在element-ui网站里面找这些指令
  • 3在表单item项中通过prop属性绑定不同的校验规则
<!--用户名区域-->                
<el-form-item prop="username">                    
	<el-input v-model="loginForm.username" prefix-icon="el-icon-user-solid"></el-input>                
</el-form-item>
9.实现表单的重置功能
  • 1.为表单el-form添加一个ref引用ref=“loginFormRef”,这个引用的值就是这个组件的一个实例对象可以通过ref直接获取对表单的引用
  • 2.然后在methods中通过this访问到this.$refs.loginFormRef.然后调用resetFields()方法实现重置表单
10.实现登录前表单数据的预验证

再发起请求前先对表单数据发起一个验证,验证通过再向服务器发起这次网络请求,否则要向用户提示这个数据不合法
思路:点击登录时,这个对象绑定一个单击事件,通过调用表单的某个函数来验证【@click=“login”】
在这里插入图片描述
validate函数接收一个回调函数从而拿到验证的结果valid
通过valid的布尔值来知道验证通过还是失败了

11.配置axios发起登陆请求
  • 先在main.js对axios进行全局配置`
/* 对axios进行全局配置,因为表单验证完要发起网络请求了 */
import axios from 'axios'
//配置请求的根路径
axios.defaults.baseURL='http://127.0.0.1:8888/api/private/v1/'
/*把axios这个包挂载到vue的原型对象上,这样的话vue的每一个组件都可通过this直接访问到http,从而去发起ajax请求 */
Vue.prototype.$http = axiosVue.config.productionTip = false
  • 如果valid为true说明预验证通过,那么发起登陆请求,否则直接return不发起登录请求
    在这里插入图片描述
    (从api接口文档中可以知道post需要的两个参数都是啥)
    (要进行网络请求的前提是先把这个服务器跑起来,到这个目录下D:\Vue\vue\shizhan\material\vue_api_server\vue_api_server,在命令行窗口执行命令:
    node app.js)
  • res.meta.status是把服务器返回的promise中包含的状态码揪出来了,就是简化了一下,如果这个状态码是200说明登陆成功
12.配置Message全局弹框组件

登录成功或者失败,我们都给用户一个弹窗来提示状态

  • 1.现在plugin/element.js中导入弹框这个组件
    • import { Input,Message,Form,FormItem,Button} from 'element-ui//message导入弹框提示组件
    • Vue.prototype.$message = Message //message需要进行全局挂载,这样每个组件都可以通过this来访问message
  • 2.在login中使用弹框,上图中就用了,效果是这样的
  • 在这里插入图片描述
13.完善登录成功之后的操作
  • 1.将登录成功之后的token,保存到客户端的sessionStorage中
    • 1.1项目中除了登陆之外的其他API接口,必须在登录之后才能访问,在登陆之后访问其他接口的时候要携带着这个token去访问,
    • 1.2token只应在当前网站打开期间生效,所以将token保存在sessionStorage中,因为sessionStorage是会话期间的存储机制(localstorage是持久化的存储机制)
  • 2 .通过编程式导航跳转到后台主页,路由地址是/home【代码上面的图里面有】
  • 3.在/components文件夹下新建一个Home.vue文件,这就是主页
    • 3.1要在router/index.js中导入Home这个组件并加入一个路由规则
    • 3.2this.$router.push('/home')点击登录就可以跳转到home主页了,下面就可以准备写主页的页面了
14.路由导航守卫控制页面访问权限
  • 我们要保证必须在有登陆权限toke的情况下才可以访问主页,要是在主页突然失去了token,必须立马跳转到login页面去,这时候就需要路由导航守卫来实现这个功能
  • /router/index.js:
  • 在这里插入图片描述
15.实现退出功能

基于token的退出功能很简单,只需要销毁token就好了

// 清空token            
window.sessionStorage.clear()            
// 跳转到登录页            
this.$router.push('/login')
16.将本地代码提交到码云中(git指令)
  • 1.在vscode中打开终端,快捷键:ctrl+`(tab上面的那个键)
  • 2.git status查看当前项目中源代码的一些状态【第一部分显示的是修改过的,第二部分显示的是新增的文件】
  • 3.git add . 把所有文件全部添加到暂存区
  • 4.git status这是会发现所有文件名字都变绿色了,说明已经被添加到了暂存区
  • 5.git commit -m "完成了登录功能"把暂存区中的所有代码提交到了本地仓库中,并给了一句修改说明
  • 6.git branch查看当前所处的分支,发现处于login分支,说明刚才进行的一系列操作是在login分支中进行的,接下来我们可以把login分支中的所有代码合并到master主分支中去
  • 7.git checkout master切换到主分支,想要把login合并到master主分支中,首先要先切换到主分支,在从主分支主动合并login
  • 8.git branch检查当前的确已经到了master分支
  • 9.git merge login合并login到master
  • 10.git push把本地master中的所有代码推送到了云端的码云中
  • 11.【把本地的login分支也推送到云端】
  • 12.git checkout login切换到login分支
  • 13.git branch检查一下是不是到了login分支
  • 14.git push -u origin login第一次推送这个分支时需要加上push后面的内容,表示我们要将本地的login子分支推送到云端origin仓储里面,同时在云端叫做login,以后再修改login在要推送的时候只要写git push就可以了

4.主页布局

4.1整体布局

  • 整体布局:线上下划分,下面那部分再左右划分
  • Element-UI这里面有各种布局的源代码真的是宝藏网站了,爱了爱了太方便了
  • 记得先在/plugin/element.js里面导入container这个组件,也可以一键全局导入
/plugin/element.js
import ElementUI from 'element-ui'
Vue.use(ElementUI)
/components/Home.vue
<el-container>            
	<!--头部区域-->            
	<el-header></el-header>            
	<el-container>                
		<!--侧边栏区域-->                
		<el-aside></el-aside>                
		<!--右侧主体区域-->                
		<el-main></el-main>            
	</el-container>        
</el-container>
  • 可以通过类选择器给每一部分添加样式,可以用类名,也可以直接用el-hearder这种块名

4.2美化主页header区域

在这里插入图片描述

.el-header {        
	background-color: #373d41;        
	display: flex; // 页面flex布局        
	justify-content: space-between;  //让按钮和图片文字盒子分别占左边和右边        padding-left: 0;        
	align-items: center; // 让按钮垂直方向居中显示,不再上下都贴着边沿        color: #fff;        
	font-size: 20px;        
	> div{            
		display: flex;            
		align-items: center;            
		span {                
			margin-left: 15px; // 文字和左边的图片之间间隔            
		}            
		img {                
			width: 60px;                
			height: 60px;            
		}        
	}    
 }

4.3左侧菜单布局

模板在element-ui里面的导航菜单里有
在这里插入图片描述

<el-container>            
	<!--侧边栏区域-->            
	<el-aside width="200px">                
		<!--侧边栏菜单区域-->                
		<el-menu background-color="#333447" text-color="#fff" active-text-color="#ffd04b">                
			<!--一级菜单-->                
			<el-submenu index="1">                    
				<!--一级菜单的模板-->                  
				<template slot="title">                        
					<!--图标-->                        
					<i class="el-icon-location"></i>                        
					<!--文本-->                        
					<span>导航一</span>                    
				</template>                    
			<!--二级菜单-->                    
			<el-menu-item index="1-1">                        
				<!--二级菜单的模板-->                        
				<template slot="title">                            	
					<!--图标-->                            
					<i class="el-icon-location"></i>                            
					<!--文本-->                            
					<span>选项1</span>                        
				</template>                    
			</el-menu-item>                
		</el-submenu>                
	</el-menu>            
</el-aside>            

4.4通过接口获取菜单数据

除了登录页面的接口,其他接口都需要token令牌才能访问,这个token令牌就是在登录页面登陆成功的时候服务器给我们返回的东西里面带的
通过axios请求拦截器添加token,保证拥有获取数据的权限
在这里插入图片描述
请求在到达服务器之前会先调用这个use函数,对请求进行预处理,给请求头对象挂载一个Authorization字段,这个字段里面装的就是我们的token,只有请求头里面有这个字段,才能访问那些有权限的页面

【main.js】
// 4.4为axios设置一个拦截器
axios.interceptors.request.use(config => {  
console.log(config)  // 在最后必须return config  
// 为请求头对象添加Token验证的Authorization字段
config.headers.Authorization = window.sessionStorage.getItem('token')  
return config
})

这样就可以保证登录之后在想要访问其他需要权限的页面时,有一个token验证

4.5获取左侧菜单栏数据

在这里插入图片描述

  • 如果meta中的status=200说明请求成功
  • data就是服务器返回的菜单列表
  • 有children说明有二级菜单
  • 在整个页面刚一加载的时候就应该立即获取左侧菜单数据,所以应该在Home.js的行为区(script)定义一个生命周期函数created()
  • 对象模型的解构赋值
    解构赋值是对赋值运算符的扩展。
    他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
    在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取
  let { baz : foo } = { baz : 'ddd' };
  // foo = 'ddd'
 【Home.vue】
 created () {        
 	this.getMenuList()        
 	this.activePath = window.sessionStorage.getItem('activePath')    	},    
 methods: {        
 	logout () {            
 		// 清空token            
 		window.sessionStorage.clear()            
 		// 跳转到登录页            
 		this.$router.push('/login')        
 		},        // 获取所有的菜单        
 	async getMenuList () {            
	 	const { data: res } = await this.$http.get('menus')  
	 	// asyncawait可以简化get的promise返回值,const{}是在解构data,赋值给res            
	 	if (res.meta.status !== 200) return this.$message.error(res.meta.msg) // 如果获取数据不成功就啥也不返回            
	 	this.menulist = res.data  //如果获取数据成功就把数据保存到menulist中          
	 	console.log(this.menulist)        
 	},

4.6通过双层v-for循环渲染左侧菜单

获取到了菜单栏数据我们得把它渲染显示到页面上,让他显示出来一层一层的菜单

  • 【渲染一级菜单】menulist数组中的每一项都是一个一级菜单,每个一级菜单中又通过children属性嵌套着二级菜单—>我们只要通过一个双层for循环来渲染各个左侧菜单就好了
    • 给一级菜单的el-submenu动态绑定一个v-for并为每一个v-for提供一个独一无二的key值(如果有id尽量用id)
    • 给一级菜单的span文本区动态绑定不同的名称item.authName
    • 一级菜单的展开,这时候是同步的,展开一个一级菜单,所有一级菜单就都展开了,这是因为大家的index都是1,只要让他们都不相同就好了:**动态绑定::index=“item.id + ‘’” **因为index只接收字符串不接收数字,所以我们要把item.id变成字符串(数值和字符串拼接的结果是一个字符串)
  • 【渲染二级菜单】
    • 二级菜单都在一级菜单的item的children属性里面,流程同上
【Home.js】

<!--一级菜单-->                
<el-submenu :index="item.id + ''" v-for="item in menulist" :key="item.id">                    
	<!--一级菜单的模板-->                    
	<template slot="title">                        
		<!--图标-->                        
		<i :class="iconsObj[item.id]"></i>                        
		<!--文本-->                        
		<span>{{item.authName}}</span>                    
	</template>                    
	<!--二级菜单-->                    
	<el-menu-item :index="'/' + subItem.path " v-for="subItem in item.children" 
	:key="subItem.id" @click="saveNavState ('/' + subItem.path)">                        
		<!--二级菜单的模板-->                        
		<template slot="title">                            
			<!--图标-->                            
			<i class="el-icon-menu"></i>                            
			<!--文本-->                            
			<span>{{subItem.authName}}</span>                        
		</template>                    
	</el-menu-item>                
</el-submenu>

效果:
在这里插入图片描述

4.7为选中项设置字体颜色并添加分类图标

1.我们要把当前选中项的文本设置特殊的高亮颜色
每次只能打开一个菜单项unique-opened
是否水平折叠收起菜单collapse
【Home.js】

<!--侧边栏菜单区域-->                
<el-menu background-color="#333447" text-color="#fff"                
active-text-color="#409EFF"  <!--设置高亮颜色-->
unique-opened="true"   <!--每次只能打开一个菜单项-->
:collapse="isCollapse"                
:collapse-transition="false"  <!--不开启折叠展开动画【4.9】-->
router   <!--激活路由模式,激活导航时,会跳转到el-submenu对应的index绑定的路径里去【4.11】>
:default-active="activePath">                
	<!--一级菜单-->
	<el-submenu>...
2.把所有二级一级菜单的图标都改成独特的
【一级菜单的】
<i :class="iconsObj[item.id]"></i>
【二级菜单的】
<i :class="el-icon-menu"></i>

一级菜单的图标我们专门给他搞一个数组来存,这些图标都在element-ui网站里面有:

data () {        
	return { // 左侧菜单数据            
	menulist: [],            
	iconsObj: {                
		125: 'el-icon-user-solid',                
		103: 'el-icon-s-claim',                
		101: 'el-icon-s-goods',                
		102: 'el-icon-s-order',                
		145: 'el-icon-s-marketing'            
	},            
	// 是否折叠            
	isCollapse: false,            
	// 被激活的链接地址            
	activePath: ''        
	}   
},
3.图标和文本之间的间距

这个要在类的样式style里面加

<style>
	.i {        
		margin-right: 10px;    
	}
</style>

4.8解决边框对齐问题

在这里插入图片描述

.el-aside {        
	background-color: #333744;        
	.el-menu {            
		border-right: none;  //把右边框线取消
	}    
}

4.9实现侧边栏的折叠与展开效果!

  • 1.侧边栏内部,菜单之前加一个盒子按钮条,准备实现当点击这个区域时就折叠,再点又展开
  • 2.给这个按钮条绑定一个单击事件toggleCollapse,这个函数会修改el-menu的isCollapse属性,这个属性就是控制是否水平折叠收起菜单的
  • 3.关闭很丑的折叠展开动画collapse-transition
  • 4.让侧边栏背景也跟着侧边栏一起折叠展开:width = “isCollapse ? ‘64px’ : ‘200px’”
	<aside :width = "isCollapse ? '64px' : '200px'">
		<div class="toggle-button" @click="toggleCollapse">|||</div>
		//给el-menu加动态collapse属性,4.7有
		<el-menu :collapse="isCollapse" :collapse-transition="false"  <!--不开启折叠展开动画-->>...
	</aside>
<script>

export default {
	data () {        
		return { 
			// 是否折叠            
			isCollapse: false,
		}
	methods: {
		// 点击按钮切换菜单的折叠与否        
		toggleCollapse () {            
			this.isCollapse = !this.isCollapse        
		},       
	}
}
</script>
	
<style>
	.toggle-button {        
		background-color: #4A5064;        
		font-size: 10px;  //文本字体大小
		line-height: 24px;  //行高
		color: #fff;    //字体颜色
		text-align: center;    //字体居中
		letter-spacing: 0.2em;      //竖线之间的间距
		//em是容器的内距容器边--到--容器内容的距离em是相对长度单位。相对于当前对象内文本的字体尺寸。
		cursor: pointer;    //鼠标放上去的时候变成一个小手
	}
</style>

在这里插入图片描述

4.10实现首页路由重定向

想要实现一到home页面就自动重定向到welcome,在home的主体区域为我们展示welcome这个组件

  • 1.在components文件夹下定义一个welcome.vue组件
  • 2.在home.vue的主体区域放一个路由占位符
<!--右侧主体区域-->            
<el-main>                
	<!--路由占位符-->                
	<router-view></router-view>            
</el-main>
  • 3.把welcome路由设置为home路由的子路由
【router/index.js】

import Welcome from '../components/Welcome.vue
const router = new VueRouter({  
	routes: [    
	{ path: '/', redirect: '/login' }, 
	// 【路由重定向】如果用户访问‘/’,那么就给他重定向到‘/login’    
	{ path: '/login', component: login }, 
	{      
		path: '/Home',      
		component: Home,      
		redirect: '/Welcome',      //路由重定向
		children: [        
			{ path: '/Welcome', component: Welcome },        
			{ path: '/users', component: Users }      
		]    
	} 
]
})

在这里插入图片描述

4.11实现侧边栏路由链接的改造

在这里插入图片描述

  • 1.在el-menu里面绑定属性:router=“true”也可以省略后面的只写个router是一个意思,激活导航时,会跳转到el-submenu对应的index绑定的路径里去,所以我们应该给index改成对应的二级菜单的path:
<el-menu-item :index="'/' + subItem.path " 
v-for="subItem in item.children"                    
:key="subItem.id" 
@click="saveNavState ('/' + subItem.path)">
  • 因为path前面是没有自带/的,所以写的时候要自己给他拼接一个
    要不然实现不了跳转
  • 如果点击“角色列表”浏览器就会自动跳转到localhost:8080/#/roles这个路径,想只改变页面的主体区域的话就像【4.10】一样给他加一个路由重定向就好了

5.主页-用户列表

5.21 修改用户状态

  • 报错
async userStateChanged (userinfo) {
      console.log(userinfo)
      const { data: res } = await this.$http.put(`users/${userinfo.id}/state/:${userinfo.mg_state}`)
      if (res.meta.status !== 200) {
        userinfo.mg_state = !userinfo.mg_state
        return this.$message.error('更新用户状态失败!')
      }
      return this.$message.success('更新用户状态成功!')
    }

注意这里的:${userinfo.mg_state}前面必须加:,否则会报错Invalid prop: type check failed for prop “enterable”. Expected Boolean, got String with value “false”.是因为布尔值要用“:“动态来表示 否则会将布尔值”false”化为字符串形式。

5.22 实现搜索功能

  • 1.把搜索框和data中的数据数据做双向绑定
  • 2.点击搜索按钮时调用获取用户列表的函数进行数据的查询

5.24 渲染添加用户的表单

【10.sublime一些快捷键】

1.分屏显示

  • view–layout–column 2可以把页面变成两列显示
  • 在每一个窗口ctrl+p然后输入想打开的文件名即可

2.文件列表的显示和隐藏

ctrl+B,ctrl+K
按住ctrl,然后按b再按k才行

Logo

快速构建 Web 应用程序

更多推荐