Vue项目实战–第一部分
文章目录
项目概述
-
PC端后台管理项目
-
功能:
-
开发模式:采用前后端分离的开发模式,其中前端项目是基于Vue技术栈的SPA(单页面)项目。
-
技术栈
- Vue
- Vue-router
- Element-UI
- Axios
- Echarts
项目初始化
前端项目初始化步骤
- 安装vue脚手架
通过vue脚手架创建项目
-
通过
vue-ui
可视化界面创建项目 -
-
自定义的可选配置项中选择
- Choose Vue version;
- Babel;
- Router;
- Linter/Formatter;
- 使用配置文件
配置Vue路由
在vue ui
内配置完成
配置Element-UI组件库
-
添加插件
-
配置axios库
- 安装依赖
初始化git远程仓库
将本地项目托管到Github或码云中
-
-
已有仓库
cd existing_git_repo git status git add . git commit -m"add files" git remote add origin git@gitee.com:gezilzq/vue_shop.git git push -u origin master
( 后台项目环境安装配置)
也可以不在本地安装后台环境
使用其他人搭建的后台
- 安装MySQL数据库
- 安装Node.js环境
- 配置项目相关信息
- 启动项目
- 使用Postman测试后台项目接口是否正常
后端接口文档
登录退出功能
登录概述
1.登录业务流程
-
在登录页面输入用户名和密码
-
调用后台接口进行验证
-
通过验证之后,根据后台的响应状态跳转到项目主页
2.登录业务的相关技术点
- http是无状态的
- 通过cookie在客户端记录状态
- 通过session在服务器端记录状态
- 通过token方式维持状态(存在跨域问题时)
*
关于登录业务所必须知道的cookie,session token的作用与区别
-
登录状态保持
如果服务器和客户端同源,建议可以使用cookie或者session来保持登录状态
如果客户端和服务器跨域了,建议使用token进行维持登录状态。 -
登录逻辑:
在登录页面输入账号和密码进行登录,将数据发送给服务器
服务器返回登录的结果,登录成功则返回数据中带有token
客户端得到token并进行保存,后续的请求都需要将此token发送给服务器,服务器会验证token以保证用户身份。
登录功能实现
在进行功能增加时,往往在新的分支内完成
添加新分支
login
,在login
分支中开发当前项目`vue_shop:
打开vue_shop终端,使用git status确定当前项目状态。
确定当前工作目录是干净的之后,创建一个分支进行开发,开发完毕之后将其合并到master
git checkout -b login
然后查看新创建的分支:
git branch
确定我们正在使用login分支进行开发
运行项目的方式
(若是运行错误,可以回到VS里进行编译,查看错误信息,基本出现报错就得自己重新配了,可能可视化界面安装时网络不好,出现问题了)
登录页面的布局
通过 Element-UI 组件实现布局
-
首先删除无用的示例,变为干净的项目结果
-
建立组件文件,编写路由
在components文件夹中新建Login.vue
组件,添加template
,script
,style
标签,style
标签中的scoped
可以防止组件之间的样式冲突,没有scoped
则样式是全局的
<template>
<div class="login_container">
</div>
</template>
<script>
export default {
}
</script>
<style lang="less" scoped>
.login_container {
background-color: #2b5b6b;
height: 100%;
}
</style>
在router.js
中导入组件并设置规则
在App.vue
中添加路由占位符
const router = new Router({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login }
]
})
当我们给Login.vu
e中的内容添加样式的时候,会报错“缺少less-loader
”,需要配置less加载器(开发依赖),安装less(开发依赖)
然后需要添加公共样式,在assets
文件夹下面添加css
文件夹,创建global.css
文件,添加全局样式
/* 全局样式表 */
html,body,#app{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
在main.js
中导入global.css
,
使得全局样式生效import "./assets/css/global.css"
然后Login.vue
中的根元素也需要设置撑满全屏(height:100%
)
随后根据登陆界面的设计进行<template>
与<style lang="less" scoped>
的编写
添加element-ui的表单组件
在plugins
文件夹中打开element.js
文件,进行elementui的按需导入
import Vue from 'vue'
import { Button, Form, FormItem, Input } from 'element-ui'
Vue.use(Button)
Vue.use(Form)
Vue.use(FormItem)
Vue.use(Input)
添加第三方字体图标
复制素材中的fonts
文件夹到assets
中,在入口文件main.js
中
导入import './assets/fonts/iconfont.css'
然后直接在 <el-input prefix-icon="iconfont icon-3702mima"></el-input>
接着添加登录盒子
最终可得以下代码(静态页面)
<template>
<div class="login_container">
<!-- 登录盒子 -->
<div class="login_box">
<!-- 头像 -->
<div class="avatar_box">
<img src="../assets/logo.png" alt="">
</div>
<!-- 登录表单 -->
<el-form>
<!-- 用户名 -->
<el-form-item>
<el-input ></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item>
<el-input></el-input>
</el-form-item>
<!-- 按钮 -->
<el-form-item class="btns">
<el-button>登录</el-button>
<el-button>重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<style lang="less" scoped>
.login_container {
background-color: #2b5b6b;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.avatar_box {
height: 130px;
width: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #ddd;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
}
}
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.btns {
display: flex;
justify-content: flex-end;
}
</style>
添加表单验证的步骤
1).给<el-form>
添加属性:rules="rules"
,rules
是一堆验证规则,定义在script
中
2).在script
中添加表单验证规则loginFormRules
3).通过<el-form-item>
的prop
属性设置验证规则<el-form-item label="活动名称" prop="name">
具体使用参考element-ui官网
data () {
return {
// 数据绑定
loginForm: {
username: 'admin',
password: '123456'
},
// 表单验证规则
loginFormRules: {
username: [
{
required: true,
message: '请输入登录名',
trigger: 'blur'
},
{
min: 3,
max: 10,
message: '登录名长度在 3 到 10 个字符',
trigger: 'blur'
}
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'blur'
},
{
min: 6,
max: 15,
message: '密码长度在 6 到 15 个字符',
trigger: 'blur'
}
]
}
}
},
实现重置按钮的功能
参考文档表单重置
方法名 说明 参数 resetFields
对整个表单进行重置,将所有字段值重置为初始值并移除校验结果 -
<el-form :model="loginForm"
ref="LoginFormRef" //添加ref属性,创建引用
:rules="loginFormRules"
label-width="0px"
class="login_form">
··········
<el-button type="info" @click="resetLoginForm">重置</el-button>
··········
// 添加行为,
methods: {
// 添加表单重置方法
resetLoginForm () {
// this=>当前组件对象,其中的属性$refs包含了设置的表单ref
// console.log(this)
this.$refs.LoginFormRef.resetFields()
},
········
}
登陆前表单数据的预验证
参考文档validate
方法名 说明 参数 validate 对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个 promise Function(callback: Function(boolean, object))
事件名称 说明 回调参数 validate 任一表单项被校验后触发 被校验的表单项 prop 值,校验是否通过,错误消息(如果存在)
login() {
//点击登录的时候先调用validate方法验证表单内容是否有误
this.$refs.LoginFormRef.validate(async valid => {
console.log(this.loginFormRules)
//如果valid参数为true则验证通过
if (!valid) {
return
}
//发送请求进行登录
········
})
}
导入axios以发送ajax请求
打开main.js
,import axios from 'axios';
设置请求的根路径:axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/';
挂载axios
:Vue.prototype.$http = axios;
// 发送请求进行登录
const { data: res } = await this.$http.post('login', this.loginForm)
// console.log(res);
if (res.meta.status !== 200) {
return console.log("登录失败:"+res.meta.msg)
}
配置Message全局弹框组件
官网文档Message组件
在plugins文件夹中打开element.js
文件,进行elementui的按需导入
import {Message} from 'element-ui'
进行全局挂载:Vue.prototype.$message = Message;
在login.vue
组件中编写弹窗代码:this.$message.error('登录失败')
登录成功之后的操作
登录成功之后,需要将后台返回的token
保存到sessionStorage
中
操作完毕之后,需要跳转到/home
//保存token
window.sessionStorage.setItem('token', res.data.token)
// 导航至/home
this.$router.push('/home')
添加一个组件Home.vue,并为之添加规则
<template>
<div>
this is home
<el-button type="info" @click="logout"> 退出 </el-button>
</div>
</template>
<script>
export default {
methods: {
logout() {
window.sessionStorage.clear()
this.$router.push('/login')
}
}
}
</script>
<style lang='less' scoped>
</style>
添加路由规则
const router = new Router({
routes: [
{ path: '/', redirect: '/login' },
{ path: '/login', component: Login },
{ path: '/home', component: Home }
]
})
添加路由守卫
如果用户没有登录,不能访问/home,如果用户通过url地址直接访问,则强制跳转到登录页面
打开router.js
import Vue from 'vue'
import Router from 'vue-router'
import Login from './components/Login.vue'
import Home from './components/Home.vue'
Vue.use(Router)
const router = new Router({
routes: [
{ path:'/', redirect:'/login'},
{ path:'/login' , component:Login },
{ path:'/home' , component:Home}
]
})
//挂载路由导航守卫,to表示将要访问的路径,from表示从哪里来,next是下一个要做的操作
router.beforeEach((to,from,next)=>{
if(to.path === '/login')
return next();
//获取token
const tokenStr = window.sessionStorage.getItem('token');
if(!tokenStr)
return next('/login');
next();
})
export default router
实现退出功能
在Home组件中添加一个退出功能按钮,给退出按钮添加点击事件,添加事件处理代码如下:
export default {
methods:{
logout(){
window.sessionStorage.clear();
this.$router.push('/login');
}
}
}
最终Login.vue
文件中的代码如下
<template>
<div class="login_container">
<!-- 登录盒子 -->
<div class="login_box">
<!-- 头像 -->
<div class="avatar_box">
<img src="../assets/logo.png" alt="">
</div>
<!-- 登录表单 -->
<el-form :model="loginForm" ref="LoginFormRef" :rules="loginFormRules" label-width="0px" class="login_form">
<!-- 用户名 -->
<el-form-item prop="username">
<el-input v-model="loginForm.username" prefix-icon="iconfont icon-user" ></el-input>
</el-form-item>
<!-- 密码 -->
<el-form-item prop="password">
<el-input type="password" v-model="loginForm.password" prefix-icon="iconfont icon-3702mima"></el-input>
</el-form-item>
<!-- 按钮 -->
<el-form-item class="btns">
<el-button type="primary" @click="login">登录</el-button>
<el-button type="info" @click="resetLoginForm">重置</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
export default {
data() {
return {
//数据绑定
loginForm: {
username: 'admin',
password: '123456'
},
//表单验证规则
loginFormRules: {
username: [
{ required: true, message: '请输入登录名', trigger: 'blur' },
{
min: 3,
max: 10,
message: '登录名长度在 3 到 10 个字符',
trigger: 'blur'
}
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{
min: 6,
max: 15,
message: '密码长度在 6 到 15 个字符',
trigger: 'blur'
}
]
}
}
},
//添加行为,
methods: {
//添加表单重置方法
resetLoginForm() {
//this=>当前组件对象,其中的属性$refs包含了设置的表单ref
// console.log(this)
this.$refs.LoginFormRef.resetFields()
},
login() {
//点击登录的时候先调用validate方法验证表单内容是否有误
this.$refs.LoginFormRef.validate(async valid => {
console.log(this.loginFormRules)
//如果valid参数为true则验证通过
if (!valid) {
return
}
//发送请求进行登录
const { data: res } = await this.$http.post('login', this.loginForm)
// console.log(res);
if (res.meta.status !== 200) {
return this.$message.error('登录失败:' + res.meta.msg) //console.log("登录失败:"+res.meta.msg)
}
this.$message.success('登录成功')
console.log(res)
//保存token
window.sessionStorage.setItem('token', res.data.token)
// 导航至/home
this.$router.push('/home')
})
}
}
}
</script>
<style lang="less" scoped>
.login_container {
background-color: #2b5b6b;
height: 100%;
}
.login_box {
width: 450px;
height: 300px;
background: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
.avatar_box {
height: 130px;
width: 130px;
border: 1px solid #eee;
border-radius: 50%;
padding: 10px;
box-shadow: 0 0 10px #ddd;
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
img {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #eee;
}
}
}
.login_form {
position: absolute;
bottom: 0;
width: 100%;
padding: 0 20px;
box-sizing: border-box;
}
.btns {
display: flex;
justify-content: flex-end;
}
</style>