使用vue搭建应用六实现登录页
1.js_cookie
js-cookie插件是一个JS操作cookie的插件
安装
yarn add js-cookie
使用
写入 Cookies.set('name', 'value');
读取 Cookies.get('name');
删除 Cookies.remove('name');
2.http请求
(1)模块封装
在src下添加目录 utils,添加 global.js
/** * 全局常量、方法封装模块 * 通过原型挂载到Vue属性 * 通过 this.Global 调用 */ export const baseUrl = 'http://localhost:8081' export default { baseUrl }
在src下添加目录 http
config.js
import { baseUrl } from '@/utils/global' export default { method: 'get', // 基础url前缀 baseUrl: baseUrl, // 请求头信息 headers: { 'Content-Type': 'application/json;charset=UTF-8' }, // 参数 data: {}, // 设置超时时间 timeout: 10000, // 携带凭证 withCredentials: true, // 返回数据类型 responseType: 'json' }
axios.js axios封装
import axios from 'axios'; import config from './config'; import Cookies from "js-cookie"; import router from '@/router' export default function $axios(options) { return new Promise((resolve, reject) => { const instance = axios.create({ baseURL: config.baseUrl, headers: config.headers, timeout: config.timeout, withCredentials: config.withCredentials }) // request 请求拦截器 instance.interceptors.request.use( config => { let token = Cookies.get('token') // 发送请求时携带token if (token) { config.headers.token = token } else { // 重定向到登录页面 router.push('/login') } return config }, error => { // 请求发生错误时 console.log('request:', error) // 判断请求超时 if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) { console.log('timeout请求超时') } // 需要重定向到错误页面 const errorInfo = error.response console.log(errorInfo) if (errorInfo) { error = errorInfo.data // 页面那边catch的时候就能拿到详细的错误信息,看最下边的Promise.reject const errorStatus = errorInfo.status; // 404 403 500 ... router.push({ path: `/error/${errorStatus}` }) } return Promise.reject(error) // 在调用的那边可以拿到(catch)你想返回的错误信息 } ) // response 响应拦截器 instance.interceptors.response.use( response => { return response.data }, err => { if (err && err.response) { switch (err.response.status) { case 400: err.message = '请求错误' break case 401: err.message = '未授权,请登录' break case 403: err.message = '拒绝访问' break case 404: err.message = `请求地址出错: ${err.response.config.url}` break case 408: err.message = '请求超时' break case 500: err.message = '服务器内部错误' break case 501: err.message = '服务未实现' break case 502: err.message = '网关错误' break case 503: err.message = '服务不可用' break case 504: err.message = '网关超时' break case 505: err.message = 'HTTP版本不受支持' break default: } } console.error(err) return Promise.reject(err) // 返回接口返回的错误信息 } ) // 请求处理 instance(options).then(res => { resolve(res) return false }).catch(error => { reject(error) }) }) }
modules/login.js 系统登录模块
// 登录接口 export function login() { const loginData = { "code": 304, "msg": "登录失败", "data": { "id": 1, "userId": 1, "token": "1111111111" } } /* const loginData = { "code": 200, "msg": "登录成功", "data": { "id": 1, "userId": 1, "token": "1111111111" } } */ return { url: 'login', type: 'post', data: loginData } } // 登出接口 export function logout() { const logoutData = { "code": 200, "msg": null, "data": { } } return { url: 'logout', type: 'get', data: logoutData } }
api.js 接口统一集成模块
import * as login from './modules/login' export default { login }
index.js 导入所有接口
import api from './api' const install = Vue => { if (install.installed) return; install.installed = true; Object.defineProperties(Vue.prototype, { // 注意,此处挂载在 Vue 原型的 $api 对象上 $api: { get() { return api } } }) } export default install
(2)应用
main.js
webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import api from './http' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.config.productionTip = false Vue.use(ElementUI) Vue.use(api) // 注册使用API模块 /* eslint-disable no-new */ new Vue({ el: '#app', router, render: h => h(App) })
3.登录
view/login.vue
<template> <el-form :model="loginForm" :rules="fieldRules" ref="loginForm" label-position="left" label-width="0px" class="demo-ruleForm login-container" > <span class="tool-bar"></span> <h2 class="title" style="padding-left:22px;">系统登录</h2> <el-form-item prop="account"> <el-input type="text" v-model="loginForm.account" auto-complete="off" placeholder="账号"></el-input> </el-form-item> <el-form-item prop="password"> <el-input type="password" v-model="loginForm.password" auto-complete="off" placeholder="密码"></el-input> </el-form-item> <el-form-item style="width:100%;"> <el-button type="primary" style="width:48%;" @click.native.prevent="reset">重 置</el-button> <el-button type="primary" style="width:48%;" @click.native.prevent="login" :loading="loading" >登 录</el-button> </el-form-item> </el-form> </template> <script> import Cookies from "js-cookie"; export default { name: "Login", data() { return { loading: false, loginForm: { account: "admin", password: "admin" }, fieldRules: { account: [{ required: true, message: "请输入账号", trigger: "blur" }], password: [{ required: true, message: "请输入密码", trigger: "blur" }] }, checked: true }; }, methods: { login() { this.loading = true; let userInfo = { account: this.loginForm.account, password: this.loginForm.password }; this.$api.login .login(userInfo) .then(res => { // 调用登录接口 if (res.code != 200) { this.$message({ message: res.msg, type: "error" }); } else { this.$message({ message: res.msg, type: "success" }); console.log(res); Cookies.set("token", res.data.token); // 放置token到Cookie sessionStorage.setItem("user", userInfo.account); // 保存用户到本地会话 this.$router.push("/"); // 登录成功,跳转到主页 } this.loading = false; }) .catch(res => { this.$message({ message: res.message, type: "error" }); }); }, reset() { this.$refs.loginForm.resetFields(); } } }; </script> <style lang="scss" scoped> .login-container { -webkit-border-radius: 5px; border-radius: 5px; -moz-border-radius: 5px; background-clip: padding-box; margin: 100px auto; width: 350px; padding: 35px 35px 15px 35px; background: #fff; border: 1px solid #eaeaea; box-shadow: 0 0 25px #cac6c6; .title { margin: 0px auto 30px auto; text-align: center; color: #505458; } } </style>
4.测试
mock封装
在src下添加目录 mock
index.js
import Mock from 'mockjs' import { baseUrl } from '@/utils/global' import * as login from './modules/login' // 1. 开启/关闭[所有模块]拦截, 通过调[openMock参数]设置. // 2. 开启/关闭[业务模块]拦截, 通过调用fnCreate方法[isOpen参数]设置. // 3. 开启/关闭[业务模块中某个请求]拦截, 通过函数返回对象中的[isOpen属性]设置. let openMock = true // let openMock = false fnCreate(login, openMock) /** * 创建mock模拟数据 * @param {*} mod 模块 * @param {*} isOpen 是否开启? */ function fnCreate(mod, isOpen = true) { if (isOpen) { for (var key in mod) { ((res) => { if (res.isOpen !== false) { let url = baseUrl if (!url.endsWith("/")) { url = url + "/" } url = url + res.url Mock.mock(new RegExp(url), res.type, (opts) => { opts['data'] = opts.body ? JSON.parse(opts.body) : null delete opts.body console.log('\n') console.log('%cmock拦截, 请求: ', 'color:blue', opts) console.log('%cmock拦截, 响应: ', 'color:blue', res.data) return res.data }) } })(mod[key]() || {}) } } }
modules/login.js 系统登录模块
// 登录接口 export function login() { const loginData = { "code": 304, "msg": "登录失败", "data": null } return { url: 'login', type: 'post', data: loginData } }
启动执行 npm run dev
浏览器打开 http://localhost:8080/#/login
修改modules/login.js
// 登录接口 export function login() { const loginData = { "code": 200, "msg": "登录成功", "data": { "id": 1, "userId": 1, "token": "1111111111" } } return { url: 'login', type: 'post', data: loginData } }