打开别人项目:安装依赖,有两个依赖环境,同时运行前后端两个服务
npm install
cd client
npm install
npm run dev
项目开始:
在项目中创建文件夹node-demo\node-app
在node-app 中使用cmd: npm init, 操作如下
package name: (app)
version: (1.0.0)
description: restful api
entry point: (index.js) server.js
test command:
git repository:
keywords:
author: yyz
license: (ISC)
About to write to H:\web\vue-ele-demo\node-demo\node-app\package.json:
{
"name": "app",
"version": "1.0.0",
"description": "restful api",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "yyz",
"license": "ISC"
}
Is this OK? (yes)
拥有package.js 在cmd 输入 code . 进入VScode
使用VSCODE的终端,新建server.js,安装express
npm install express
出现node model 文件夹说明装好了
server.js配置
// 引入express
const express = require("express")
// 实例化app
const app = express()
// 设置端口号
const port = process.env.PORT || 5000
app.listen(port, () =>{
console.log(`Server is runing on port ${port}`)
})
// 设置路由, 找到根路径
app.get("/", (req, res) =>{
res.send('Hello world')
})
node server.js 运行nodejs
npm install nodemon -g 安装nodemon
如果安装了好了 使用 nodemon server.js 启动
作用是热启动,修改文件会自动重启node
修改package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js",
"server": "nodemon server.js"
}
npm run start 线上用的
npm run server 启动nodemon本地测试用
localhost:5000 可以打开node本地服务器
远程连接mongoDB
官网
注册账号
[email protected]
密码是长的那个
创建project 创建cluster
cluster创建好后 添加user
root 密码短的
最后connect
拷贝connect String
回到项目终端 安装mongodb
npm install mongoose
npm install mongoose -save
回到server.js 引入mongoose,连接mgdb
const mongoose = require("mongoose")
// mongoose 连接
mongoose
.connect(
"mongodb+srv://root:[email protected]/test?retryWrites=true&w=majority",
{
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false
}
)
.then(() => {
console.log("mongoDB has been connected");
})
.catch(err => console.log(err));
为便于管理,创建config文件夹,里面新建key.js
// 让外部能正常引入
// 让外部能正常引入
module.exports = {
mongoURL:
"mongodb+srv://root:[email protected]/test?retryWrites=true&w=majority"
};
回到server.js
// 引入配置文件
const dbURL = require("./config/key").mongoURL
URL string改成dbURL
// mongoose 连接
mongoose
.connect(
// 可以简化了
dbURL,
{
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false
}
)
.then(() => {
console.log("mongoDB has been connected");
})
.catch(err => console.log(err));
在mongodb cluster 里的 collection能看到你存储的数据
实现接口,新建两个文件夹 routers/api api下创建users.js用于login和register
user.js hello world , 注意module.exports = router;要放到最后
// login and register
const express = require("express");
const router = express.Router();
/* test 接口
* $route GET api/user/test
* @desc 返回请求的数据
* @access public
*/
rou
ter.get('/test', (req, res) =>{
res.json({
msg: 'it works'
})
})
module.exports = router;
server.js 引入users
// 引入users.js
const users = require('./routers/api/users')
// 使用router
app.use("/api/users", users)
访问localhost:5000/api/users就会调用users
localhost:5000/api/users/test 就会返回{“msg”:“it works”}
创建models文件,里面创建User.js
// 引入mongoose 因为要存进mongoose里去
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
// 需要什么字段就写什么
name: {
type: String,
required: true
},
password: {
type: String,
required: true
},
email: {
type: String,
required: true
},
avatar: {
type: String,
},
date:{
type: Date,
// 默认时间就是当前时间,不用取处理时间了
default:Date.now
}
});
// 创建模型 继承UserSchema
module.exports = User = mongoose.model("users", UserSchema)
搭建注册接口,为了得到post结果,安装npm install body-parser
在server.js引入body-parser和加入两行添加中间件
const bodyParser = require("body-parser")
加入两行,注意要放在router前面!!
// 使用body-parser中间件
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
返回api/users.js,引入model
// 引入model
const Users = require("../../models/User")
写注册接口
/* 注册 接口
* $route Post api/users/register
* @desc 用户注册
* @access public
*/
router.post('/register', (req, res) => {
// 查询数据库中是否拥有邮箱
Users.findOne({ email: req.body.email }).then(user => {
// 如果能查到就返回一个user
// 如果邮箱已经注册,返回错误信息
if (user) {
return res.status(400).json({
msg: '邮箱已被注册'
})
}else{
// 创建一个User
const newUser = new User({
name: req.body.name,
email: req.body.email,
avatar,
password: req.body.password
})
}
})
})
密码要加密,安装npm install bcrypt-nodejs
在users.js引入
const bcrypt = require('bcrypt-nodejs')
写完注册接口
router.post('/register', (req, res) => {
// 查询数据库中是否拥有邮箱
Users.findOne({ email: req.body.email }).then(user => {
// 如果能查到就返回一个user
// 如果邮箱已经注册,返回错误信息
if (user) {
return res.status(400).json({
msg: '邮箱已被注册'
})
} else {
// 创建一个User
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
})
// bcrypt加密
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, null, (err, hash) => {
if (err) throw err
newUser.password = hash
// 保存user,成功返回user json,失败catch
newUser.save().then(user => {
res.json(user).catch(err => {
console.log.err
})
})
})
})
}
})
})
查API点这里,bcrypt的hash新版变成4个参数了
去postman那里测试,测试成功
去mongodb查看collection保存的数据,官网
第三方库 gravatar 安装npm i gravatar
在要使用的users.js里面 引入gravatar
// 引入gravatar
var gravatar = require('gravatar');
const avatar = gravatar.url 添加到注册接口中
router.post('/register', (req, res) => {
// 查询数据库中是否拥有邮箱
Users.findOne({ email: req.body.email }).then(user => {
// 如果能查到就返回一个user
// 如果邮箱已经注册,返回错误信息
if (user) {
return res
.status(400)
.json({
msg: '邮箱已被注册'
})
.catch(err => {
console.log(err)
})
} else {
// 创建一个User
// mm是有一个头像
const avatar = gravatar.url(req.body.email, {s: '200', r: 'pg', d: 'mm'});
const newUser = new User({
name: req.body.name,
email: req.body.email,
avatar,
password: req.body.password
})
// bcrypt加密
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, null, (err, hash) => {
if (err) throw err
newUser.password = hash
// 保存user,成功返回user json,失败catch
newUser.save().then(user => {
res.json(user).catch(err => {
console.log(err)
})
})
})
})
}
})
})
去postman测试,会返回一个avatar会返回一个url,效果图
gravatar官网,去注册一个账号 邮箱 [email protected] 用户名 yangyizhou 密码 长的,修改gravatar网站的头像可以返回你的上传的头像,但是我们只是要个他们的默认头像
写登录接口,
/* 登录 接口
* $route Post api/users/login
* @desc 返回token jwt passport
* @access public
*/
router.post('/login', (req, res) => {
const email = req.body.email
const password = req.body.password
// 查询数据库,会返回user
Users.findOne({ email }).then(user => {
// 如果user不存在
if (!user) {
return res.status(404).json({
code: 404,
msg: '用户不存在'
})
}
// bcrypt密码匹配
bcrypt.compare(password, user.password, function(err, isMatch) {
if (isMatch) {
return res.json({
code: 200,
msg: 'success'
})
} else {
return res.status(400).json({
code: 901,
msg: '密码错误'
})
}
})
})
})
因为bcrypt用的是bcryptnodejs的,所以要用function这种写法,注意function的参数不要用res,会覆盖返回json的res
实现token,使用jsonwebtoken, npm install jsonwebtoken
在要用的地方引入依赖
const jwt = require('jsonwebtoken')
在key.js中加入secret
module.exports = {
mongoURL:
'mongodb+srv://root:[email protected]/test?retryWrites=true&w=majority',
secretOrKey: 'secret'
}
再要用的地方加入引入
const keys = require("../../config/key");
token的获取方式
if (isMatch) {
// 获取token
// 定义规则
const rule = { id: user.id, name: user.name }
jwt.sign(
rule,
keys.secretOrKey,
{ expiresIn: 3600 },
(err, token) => {
res.json({
code: 200,
token: token
})
}
)
}
完整登录接口
/* 登录 接口
* $route Post api/users/login
* @desc 返回token jwt passport
* @access public
*/
router.post('/login', (req, res) => {
const email = req.body.email
const password = req.body.password
// 查询数据库,会返回user
Users.findOne({ email }).then(user => {
// 如果user不存在
if (!user) {
return res.status(404).json({
code: 404,
msg: '用户不存在'
})
}
// bcrypt密码匹配
bcrypt.compare(password, user.password, function(err, isMatch) {
if (isMatch) {
// 获取token
// 定义规则
const rule = { id: user.id, name: user.name }
jwt.sign(
rule,
keys.secretOrKey,
{ expiresIn: 3600 },
(err, token) => {
res.json({
code: 200,
token: token
})
}
)
} else {
return res.status(901).json({
code: 901,
msg: '密码错误'
})
}
})
})
})
获取用户信息,安装passport,
npm install passport-jwt,
npm install passport,
npm install passport-jwt passport
在server.js中引入passport
const passport = require('passport')
// passport 初始化
app.use(passport.initialize())
在config文件夹下新建passport.js
server.js代码在初始化下面写,把passport作为参数传递给/config/passport.js
require("./config/passport")(passport)
config/passport.js配置信息
const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt
const mongoose = require('mongoose')
// 要用User里面的users
const User = mongoose.model('users')
const keys = require('../config/key').secretOrKey
const opts = {}
// 配置信息 调用jwtFromRequest验证
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
opts.secretOrKey = keys
// 函数引进
module.exports = passport => {
//这个passport是server.js那里传进来的
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
console.log(jwt_payload)
})
)
}
在api/user.js引入passport
const passport = require("passport")
将current接口改写成,加入验证方式
router.get(
'/current',
passport.authenticate('jwt', { session: false }),
(req, res) => {
}
)
用postman测试,发现不能通过验证的,
回到获取token那里,token前面上Bearer 字符串,才能验证通过
jwt.sign(
rule,
keys.secretOrKey,
{ expiresIn: 3600 },
(err, token) => {
res.json({
code: 200,
token: "Bearer " + token
})
}
)
get,注意参数Authorization在Header加。
如果能终端能获取到信息,那么说明成功了
回到passport.js 修改JwtStrategy
module.exports = passport => {
//这个passport是server.js那里传进来的
passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
// 能显示出来就行了
// console.log(jwt_payload)
User.findById(jwt_payload.id)
.then(user => {
// 如果用户存在,把user返回去
if (user) {
return done(null, user)
} else {
return done(null, false)
}
})
.catch(err => {
console.log(err)
})
})
)
}
获取用户信息接口,调成返回json
/* 获取用户信息 接口
* 验证token
* $route GET api/users/current
* @desc return current user info
* @access Private
*/
router.get(
'/current',
passport.authenticate('jwt', { session: false }),
(req, res) => {
// 通过验证返回用户信息
res.json({
id: req.user.id,
name: req.user.name,
email: req.user.email
})
}
)
添加身份字段,修改User.js的Schema添加identity
// Create Schema
const UserSchema = new Schema({
// 需要什么字段就写什么
name: {
type: String,
required: true
},
password: {
type: String,
required: true
},
email: {
type: String,
required: true
},
avatar: {
type: String
},
date: {
type: Date,
// 默认时间就是当前时间,不用取处理时间了
defa,ult: Date.now
},
identity:{
type: String
}
})
回到user.js, 在newUser的时候要多添加一个字段
const newUser = new User({
name: req.body.name,
email: req.body.email,
avatar,
password: req.body.password,
identity: req.body.identity
})
我们还希望token能存储多一点数据,修改规则
const rule = {
id: user.id,
name: user.name,
avatar: user.avatar,
identity: user.identity
}
最后获取用户信息加上 identity
// 通过验证返回用户信息
res.json({
code: 200,
msg: {
id: req.user.id,
name: req.user.name,
email: req.user.email,
identity: req.user.identity
}
})
然后重新注册,postman进行验证
登陆注册接口搞定~!
接下来是数据的CRUD
model文件夹下新建Profiles.js
// 引入mongoose 因为要存进mongoose里去
const mongoose = require('mongoose')
const Schema = mongoose.Schema
// Create Schema
const ProfileSchema = new Schema({
// 需要什么字段就写什么
type: {
type: String
},
describe: {
type: String
},
incode: {
type: String,
required: true
},
expend: {
type: String,
required: true
},
cash: {
type: String,
required: true
},
remark: {
type: String
},
date: {
type: Date,
default: Date.now
}
})
// 创建模型 继承UserSchema
module.exports = Profile = mongoose.model('profile', ProfileSchema)
api下面创建profiles.js,写上一行,不然在server.js用不了
module.exports = router
回到server.js进行配置
// 引入profiles.js
const profiles = require('./routers/api/profiles')
// 使用router
app.use('/api/profiles', profiles)
回到profies.js 设置要用到的引入
// login and register
const express = require('express')
const router = express.Router()
const passport = require('passport')
const Profile = require('../../models/Profiles')
/* test 接口
* $route GET api/users/test
* @desc 返回请求的数据
* @access public
*/
router.get('/test', (req, res) => {
res.json({
msg: 'it works'
})
})
module.exports = router
创建信息接口
/* 创建信息 接口
* $route POST api/profiles/add
* @desc 创建信息
* @access Private
*/
router.post(
'/add',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const profileFields = {}
if (req.body.type) profileFields.type = req.body.type
if (req.body.describe) profileFields.describe = req.body.describe
if (req.body.income) profileFields.income = req.body.income
if (req.body.expend) profileFields.expend = req.body.expend
if (req.body.cash) profileFields.cash = req.body.cash
if (req.body.remark) profileFields.remark = req.body.remark
// 新建profile对象保存
new Profile(profileFields).save()
.then(profile =>{
// 如果存成功返回json
res.json(profile)
})
}
)
获取所有信息接口
/* 获取所有信息 接口
* $route GET api/profiles
* @desc 获取所有信息
* @access Private
*/
router.get(
'/',
passport.authenticate('jwt', { session: false }),
(req, res) => {
Profile.find()
.then(profiles => {
if (!profiles) {
return res.status(902).json({
msg: '没有profile内容'
})
} else {
res.json(profiles)
}
})
.catch(err => {
console.log(err)
res.status(404).json(err)
})
}
)
获取单个信息接口
/* 获取单个信息 接口
* $route GET api/profiles/:id
* @desc 获取单个信息
* @access Private
*/
router.get(
'/:id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
Profile.findOne({_id: req.params.id})
.then(profiles => {
if (!profiles) {
return res.status(902).json({
msg: '没有profile内容'
})
} else {
res.json(profiles)
}
})
.catch(err => {
console.log(err)
res.status(404).json(err)
})
}
)
编辑接口
/* 编辑信息 接口
* $route POST api/profiles/edit
* @desc 编辑信息
* @access Private
*/
router.post(
'/edit/:id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
const profileFields = {}
if (req.body.type) profileFields.type = req.body.type
if (req.body.describe) profileFields.describe = req.body.describe
if (req.body.income) profileFields.income = req.body.income
if (req.body.expend) profileFields.expend = req.body.expend
if (req.body.cash) profileFields.cash = req.body.cash
if (req.body.remark) profileFields.remark = req.body.remark
// 查找id
Profile.findOneAndUpdate(
{
_id: req.params.id
},
{
$set: profileFields
},
{
new: true
}
).then(profile => {
res.json(profile)
})
}
)
删除接口
/* 删除信息 接口
* $route POST api/profiles/delete/:id
* @desc 删除信息
* @access Private
*/
router.delete(
'/delete/:id',
passport.authenticate('jwt', { session: false }),
(req, res) => {
Profile.findOneAndRemove({
_id: req.params.id
})
.then(profile => {
res.status(200).json({
msg: '删除成功',
body: profile
})
})
.catch(err => res.status(404).json('删除失败'))
}
)
搭建前端
回到项目总根目录(就是之前操作的根目录) 打开终端,vue create client, 安装Router,vuex
前后端连载, 在根目录安装npm install concurrently, 用于将多个不同的vue项目启动绑定到一个终端 ,首先修改client的package.js 加入start的启动 主要是启动serve
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"start": "npm run serve"
}
修改根项目的package.js,加入三个
"scripts": {
"client-install": "npm install --prefix client",
"client": "npm start --prefix client",
"start": "node server.js",
"server": "nodemon server.js",
"dev": "concurrently \"npm run server\" \"npm run client\""
}
client-install表示的是依赖模块
"client"表示启动client项目的start
npm ru ndev 就可以开启绑定的指令
正式进入client项目,删除assert,components,views的东西
在views文件夹下面创建index.vue
<template>
<div class="index">
初始化
</div>
</template>
<script>
export default {
name: 'index',
components: {}
};
</script>
<style scoped></style>
router下的index.js引入
import Index from './views/Index.vue'
在配置router
routes = [
{
path: '/',
redirect: '/index',
},
{
path: '/index',
name: 'index',
components: Index
}
]
然后写好404.vue,Register.vue,配置router
404.vue
<template>
<div class="notfound">
<img src="../assets/404.gif" alt="">
</div>
</template>
<script>
export default {
name: 'not-found',
component: {}
};
</script>
<style scoped>
.notfound{
width: 100%;
height: 100%;
overflow: hidden;
}
.notfound img{
width: 100%;
height: 100%;
}
</style>
Register.vue
<template>
<div class="register">
<!-- <section> 标签定义文档中的节(section、区段)。
比如章节、页眉、页脚或文档中的其他部分。 -->
<section class="form_container">
<div class="manage_tip">
<span class="title" style="">demo</span>
</div>
</section>
</div>
</template>
<script>
export default {
name: 'register',
component: {}
};
</script>
<style scoped>
.register {
position: relative;
width: 100%;
height: 100%;
background: url(../assets/bg.jpg) no-repeat center center;
background-size: 100% 100%;
}
.form_container {
width: 370px;
height: 210px;
position: relative;
top: 10%;
margin:0 auto;
padding: 25px;
border-radius: 5px;
text-align: center;
}
.form_container .manage_tip .title {
font-family: 'Microsoft YaHei';
font-weight: bold;
font-size: 26px;
text-align: center;
color: #fff;
}
.registerForm {
margin-top: 20px;
background-color: #fff;
padding: 20px 40px 20px 20px;
border-radius: 5px;
box-shadow: 0px 5px 10px #cccc;
}
.submit_btn {
width: 100%;
}
</style>
配置Router
import Vue from 'vue'
import Router from 'vue-router'
import Index from '../views/Index.vue'
import Register from '../views/Register'
import NotFound from '../views/404'
Vue.use(Router)
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{ path: '/', redirect: '/index' },
{ path: '/index', component: Index},
{ path: '/register', name: 'register', component: Register },
{ path: '*', name: '/404', component: NotFound}
]
})
export default router;```
应用elementUI,[官网](https://element.eleme.cn/#/)
感兴趣可以去看一下布局
比如我们要用这个注册自定义验证
先把HTML贴过来
```html
<el-form
:model="ruleForm"
status-icon
:rules="rules"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item label="密码" prop="pass">
<el-input
type="password"
v-model="ruleForm.pass"
autocomplete="off"
></el-input>
</el-form-item>
<el-form-item>
<el-button @click="resetForm('ruleForm')"
>注册</el-button
>
</el-form-item>
</el-form>
修改form表单里的:model :rules等属性
:model="registerUser"
在改其他组件里面的属性如 label prop
修改好后form表单
<el-form
:model="registerUser"
:rules="rules"
ref="registerForm"
label-width="80px"
class="registerForm"
>
<el-form-item label="用户名" prop="name">
<el-input
v-model="registerUser.name"
placeholder="请输入用户名"
></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input
v-model="registerUser.email"
placeholder="请输入email"
></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="registerUser.password"
placeholder="请输入密码"
></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="password2">
<el-input
type="password"
v-model="registerUser.password2"
placeholder="请确认密码"
></el-input>
</el-form-item>
<el-form-item label="选择身份">
<el-select
v-model="registerUser.identity"
aria-placeholder="请选择身份"
>
<el-option label="管理员" value="manage" />
<el-option label="员工" value="employee" />
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="primary" class="submit_btn"
@click="submitForm('registerForm')"
>注册</el-button
>
</el-form-item>
</el-form>
现在是显示不了的,因为Property or method no defined,
写上属性
export default {
name: 'register',
component: {},
data() {
return {
registerUser: {
name: '',
email: '',
password: '',
password2: '',
identity: ''
}
};
},
methods: {}
};
还差methods和rules没写
写rules
data() {
return {
registerUser: {
name: '',
email: '',
password: '',
password2: '',
identity: ''
},
rules: {
name: [
{
required: true,
message: '用户名不能为空',
trigger: 'blur'
},
{
min: 2,
max: 30,
message: '长度在2到30之间',
trigger: 'blur'
}
],
email: [
{
type: "email",
required: true,
message: '邮箱格式不正确',
trigger: 'blur'
}
],
password: [
{
required: true,
message: '密码不能为空',
trigger: 'blur'
}
],
password2: [
{
required: true,
message: '密码不能为空',
trigger: 'blur'
}
]
}
};
},
在data里return之上自定义验证函数
var validatePass2 = (rule, value, callback) => {
if (value !== this.registerUser.password) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
在return下面的rules里的password2里加上validator
password2: [
{
required: true,
message: '确认密码不能为空',
trigger: 'blur'
},
{
validator:validatePass2
}
]
}
验证写完了,写加载效果
去ele官网查 loading加载
点击注册还要有axios请求,所以在client下面 npm i aixos
在src下面新建http.js文件,在里面引入axios
import axios from 'axios'
// 请求拦截
// 响应拦截
export default axios;
main.js中也要引入axios
import axios from './http'
同时引入全局
Vue.prototype.$axios = axios;
Loading 还可以以服务的方式调用。回到http.js 引入 Loading 服务
import { Loading } from 'element-ui';
写loading方法
let loading;
function startLoading(){
loading = Loading.service({
lock: true,
text: '拼命加载中',
background: 'rgba(0,0,0,7)'
});
}
function endLoading(){
loading.close();
}
引入消息提示
import { Message } from 'element-ui';
http.js
import axios from 'axios'
import { Loading } from 'element-ui';
import { Message } from 'element-ui';
let loading;
function startLoading(){
loading = Loading.service({
lock: true,
text: '拼命加载中',
background: 'rgba(0,0,0,7)'
});
}
function endLoading(){
loading.close();
}
// 请求拦截
axios.interceptors.request.use(config => {
//加载动画
startLoading();
return config;
}, error => {
return Promise.reject(error)
})
// 响应拦截
export default axios;
axios.interceptors.response.use(response => {
//结束加载动画
endLoading();
return response;
}, error => {
endLoading();
Message.error(error.response.data);
return Promise.reject(error)
})
前端配置跨域请求,在client文件下面创建vue.config.js
配置跨域请求
const path = require('path')
const debug = process.env.NODE_ENV !== 'production'
module.exports = {
publicPath: '/', // 根域上下文目录
outputDir: 'dist', // 构建输出目录
assetsDir: 'assets', // 静态资源目录 (js, css, img, fonts)
lintOnSave: false, // 是否开启eslint保存检测,有效值:ture | false | 'error'
runtimeCompiler: true, // 运行时版本是否需要编译
transpileDependencies: [], // 默认babel-loader忽略mode_modules,这里可增加例外的依赖包名
productionSourceMap: true, // 是否在构建生产包时生成 sourceMap 文件,false将提高构建速度
configureWebpack: config => { // webpack配置,值位对象时会合并配置,为方法时会改写配置
if (debug) { // 开发环境配置
config.devtool = 'cheap-module-eval-source-map'
} else { // 生产环境配置
}
// Object.assign(config, { // 开发生产共同配置
// resolve: {
// alias: {
// '@': path.resolve(__dirname, './src'),
// '@c': path.resolve(__dirname, './src/components'),
// 'vue$': 'vue/dist/vue.esm.js'
// }
// }
// })
},
chainWebpack: config => { // webpack链接API,用于生成和修改webapck配置,https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
if (debug) {
// 本地开发配置
} else {
// 生产开发配置
}
},
parallel: require('os').cpus().length > 1, // 构建时开启多进程处理babel编译
pluginOptions: { // 第三方插件配置
},
pwa: { // 单页插件相关配置 https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
},
devServer: {
open: true,
host: 'localhost',
port: 8081,
https: false,
hotOnly: false,
proxy: { // 配置跨域
'/api': {
target: 'http://localhost:5000/api/',
ws: true,
changOrigin: true,
pathRewrite: {
'^/api': ''
}
}
},
before: app => { }
}
}
target那里改请求地址,记得要重启
回到Register.vue
写axios请求
submitForm(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
this.$axios
.post('/api/users/register', this.registerUser)
.then(res => {
// 注册成功
this.$message({
message: '注册成功!',
type: 'success'
});
this.$router.push('/login');
});
} else {
console.log('error submit!!');
return false;
}
});
}
测试,成功!
写登录页面 Login.vue,配置router
<template>
<div class="login">
<!-- <section> 标签定义文档中的节(section、区段)。
比如章节、页眉、页脚或文档中的其他部分。 -->
<section class="form_container">
<div class="manage_tip">
<span class="title" style="">demo</span>
<el-form
:model="loginUser"
:rules="rules"
ref="loginForm"
label-width="60px"
class="loginForm"
>
<el-form-item label="邮箱" prop="email">
<el-input
type="email"
v-model="loginUser.email"
placeholder="请输入email"
></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
type="password"
v-model="loginUser.password"
placeholder="请输入密码"
></el-input>
</el-form-item>
<el-form-item>
<el-button
type="primary"
class="submit_btn"
@click="submitForm('loginForm')"
>登陆</el-button
>
</el-form-item>
<div class="tiparea">
<p>
还有没有账号?现在<router-link to="/register"
>注册</router-link
>
</p>
</div>
</el-form>
</div>
</section>
</div>
</template>
<script>
export default {
name: 'login',
component: {},
data() {
return {
loginUser: {
email: '',
password: ''
},
rules: {
email: [
{
type: 'email',
required: true,
message: '邮箱格式不正确',
trigger: 'blur'
}
],
password: [
{
required: true,
message: '密码不能为空',
trigger: 'blur'
}
]
}
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
this.$axios
.post('/api/users/login', this.loginUser)
.then(res => {
// 登录成功
this.$message({
message: '登录成功!',
type: 'success'
});
//获取token
const { token } = res.data;
// 存储到ls
localStorage.setItem('eleToken', token);
this.$router.push('/login');
})
.catch(error => {
// 如果错误 打印处错误信息
console.log(error.response);
});
} else {
console.log('error submit!!');
return false;
}
});
}
}
};
</script>
<style scoped>
.login {
position: relative;
width: 100%;
height: 100%;
background: url(../assets/bg.jpg) no-repeat center center;
background-size: 100% 100%;
}
.form_container {
width: 370px;
height: 210px;
position: relative;
top: 10%;
margin: 0 auto;
padding: 25px;
border-radius: 5px;
text-align: center;
}
.form_container .manage_tip .title {
font-family: 'Microsoft YaHei';
font-weight: bold;
font-size: 26px;
text-align: center;
color: #fff;
}
.loginForm {
margin-top: 20px;
background-color: #fff;
padding: 20px 40px 20px 20px;
border-radius: 5px;
box-shadow: 0px 5px 10px #cccc;
}
.submit_btn {
width: 100%;
}
.tiparea {
text-align: right;
font-size: 12px;
color: #333;
}
.tiparea p a {
color: #409eff;
}
</style>
const {token} es6语法 把对象解析过来
loaclstorage.setItem 保存loaclstorage
F12 Applicaiton 可以查看到localstore 存的token
路由守卫,进入router.js(默认指router的配置文件了)
import Vue from 'vue';
import Router from 'vue-router';
import Index from '../views/Index.vue';
import Register from '../views/Register';
import NotFound from '../views/404';
import Login from '../views/Login';
Vue.use(Router);
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{ path: '/', redirect: '/index' },
{ path: '/index', component: Index },
{ path: '/register', name: 'register', component: Register },
{ path: '*', name: '/404', component: NotFound },
{ path: '/login', name: 'login', component: Login }
]
});
//路由守卫
router.beforeEach((to, from, next) => {
// 如果存在返回真,如果不存在返回假
const isLogin = localStorage.eleToken ? true : false;
// 如果访问这两个页面都可以访问,否则要进行判断
if (to.path == '/login' || to.path == '/register') {
next();
}else{
// 登陆了进行跳转,否则去登陆页面
isLogin ? next() : next('/login')
}
});
export default router;
配置请求拦截和响应拦截,判断token和设置请求头
去http.js 引入router,写请求拦截和响应拦截
import axios from 'axios'
import { Loading } from 'element-ui';
import { Message } from 'element-ui';
import router from './router/index'
let loading;
function startLoading(){
loading = Loading.service({
lock: true,
text: '拼命加载中',
background: 'rgba(0,0,0,7)'
});
}
function endLoading(){
loading.close();
}
// 请求拦截
axios.interceptors.request.use(config => {
//加载动画
startLoading();
if(localStorage.eleToken){
//设置统一的请求头
config.headers.Authorization = localStorage.eleToken
}
return config;
}, error => {
return Promise.reject(error)
})
// 响应拦截
export default axios;
axios.interceptors.response.use(response => {
//结束加载动画
endLoading();
return response;
}, error => {
endLoading();
Message.error(error.response.data);
// 获取错误状态码
const {status} = error.response;
if(status == 401){
Message.error("token失效,请重新登陆!")
// 清除token
localStorage.removeItem('eleToken')
// 跳转到登陆页面
router.push('/login')
}
return Promise.reject(error)
})
安装能够解析token的模块
npm i jwt-decode
在Login.vue引入jwt-decode, 在