vue-cli
安装 ui 库(eg:pc端用element ui、移动端用 vuex)
vux
github地址
elementUI
饿了么github地址
vue-admin-template
PanJiaChen/vue-element-admin
vue前端开发项目框架搭建(node+webpack+vue)
Vue项目环境搭建总结
前端框架搭建-搭建vue环境(学习笔记)
其它:
vue-cli 3.x搭建项目以及其中vue.config.js文件的配置
Vue 创建项目后没有 webpack.config.js(vue.config.js) 文件
解决Vue-cli3没有vue.config.js文件夹及配置vue项目域名
Vue vue-config.js(字段属性详细介绍)
由于本机已有 nodejs、npm、vue-cli等,所以直接创建项目即可
参考:超级详细的Vue-cli3使用教程
vue create 文件名
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>( ) Babel // 代码编译
( ) TypeScript // ts
( ) Progressive Web App (PWA) Support // 支持渐进式网页应用程序
( ) Router // vue路由
( ) Vuex // 状态管理模式
( ) CSS Pre-processors // css预处理
( ) Linter / Formatter // 代码风格、格式校验
( ) Unit Testing // 单元测试
( ) E2E Testing // 端对端测试
一般项目开发只需要选择Babel、Router、Vuex就足够了。
module.exports = {
devServer: {
// 端口号
port: 8080,
// 配置不同的后台API地址
proxy: {
'/api': {
target: 'http://www.dzm.com',
ws: false,
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
element-ui官网:http://element-cn.eleme.io/#/zh-CN/component/installation
npm 安装
npm i element-ui -S
完整引入
在 main.js 中写入以下内容:
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
Vue.use(ElementUI);
new Vue({
el: '#app',
render: h => h(App)
});
axios中文文档|axios中文网:http://www.axios-js.com/zh-cn/docs/
vue项目中axios拦截器的使用和配置
npm install axios
import axios from 'axios'
创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
配置请求拦截器
service.interceptors.request.use({})
// request interceptor
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
配置响应拦截器
service.interceptors.response.use({})
// response interceptor
service.interceptors.response.use(
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 20000) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
输出 axios 实例
export default service
例子:
import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// create an axios instance
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// request interceptor
service.interceptors.request.use(
config => {
// do something before request is sent
if (store.getters.token) {
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
config.headers['X-Token'] = getToken()
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// response interceptor
service.interceptors.response.use(
/**
* If you want to get http information such as headers or status
* Please return response => response
*/
/**
* Determine the request status by custom code
* Here is just an example
* You can also judge the status by HTTP Status Code
*/
response => {
const res = response.data
// if the custom code is not 20000, it is judged as an error.
if (res.code !== 20000) {
Message({
message: res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
// to re-login
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
confirmButtonText: 'Re-Login',
cancelButtonText: 'Cancel',
type: 'warning'
}).then(() => {
store.dispatch('user/resetToken').then(() => {
location.reload()
})
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
src/utils/auth.js
import Cookies from 'js-cookie'
const TokenKey = 'vue_admin_template_token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
例子:
import axios from "axios";
// import * as auth from "@/plugins/auth"
import {
Notification as notification,
MessageBox as Modal,
Loading
} from "element-ui";
import store from "@/store";
import Vue from "vue";
import * as auth from "@/plugins/auth";
// Full config: https://github.com/axios/axios#request-config
// axios.defaults.baseURL = '/rms'
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
let reqNum = 0;
let loadingInstance = null;
const err = error => {
if (error.response) {
let data = error.response.data;
// const token = auth.getToken()
// console.log("------异常响应------", token)
// console.log("------异常响应------", error.response.status)
switch (error.response.status) {
case 403:
notification.error({
title: "系统提示",
message: "拒绝访问",
duration: 4000
});
break;
case 511:
Modal.alert("很抱歉,登录已过期,请重新登录", {
title: "登录已过期",
showClose: false,
confirmButtonText: "重新登录",
callback: () => {
store.dispatch("Logout");
}
});
throw new Error("Token失效,请重新登录");
case 500:
//notification.error({ message: '系统提示', description:'Token失效,请重新登录!',duration: 4})
if (data.message == "Token失效,请重新登录") {
// update-begin- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
// store.dispatch('Logout').then(() => {
// window.location.reload()
// })
Modal.alert("很抱歉,登录已过期,请重新登录", {
title: "登录已过期",
showClose: false,
confirmButtonText: "重新登录",
callback: () => {
store.dispatch("Logout");
}
});
// update-end- --- author:scott ------ date:20190225 ---- for:Token失效采用弹框模式,不直接跳转----
} else {
notification.error({
title: "系统提示",
message: data,
duration: 4000
});
}
break;
case 404:
notification.error({
title: "系统提示",
message: "很抱歉,资源未找到!",
duration: 4000
});
break;
case 504:
notification.error({
title: "系统提示",
message: "网络超时"
});
break;
case 401:
notification.error({
title: "系统提示",
message: "未授权,请重新登录",
duration: 4000
});
break;
case 302:
window.location.href = `${process.env.VUE_APP_PublicPath}api/${window.location.host.includes("it.") && !window.location.href.includes(process.env.VUE_APP_PublicPath+"a")?'oauth/':''}login?backUrl=http://${window.location.host}${process.env.VUE_APP_PublicPath}%23/`;
break;
default:
notification.error({
title: "系统提示",
message: data,
duration: 4000
});
break;
}
}
return Promise.reject(error);
};
let config = {
baseURL: process.env.VUE_APP_PublicPath.replace(/\/$/, ""),
timeout: 60 * 1000, // Timeout
withCredentials: true // Check cross-site Access-Control
};
export const _axios = axios.create(config);
// 请求拦截器
_axios.interceptors.request.use(
config => {
let cancel;
// 设置cancelToken对象
config.cancelToken = new axios.CancelToken(c => {
cancel = c;
});
//console.log(cancel);
let urlList = ['task/getTaskTypeList', '/dict/getDictItems'];
let isFilter = urlList.some(item => {
let number = config.url.indexOf(item);
return number > -1;
})
if (isFilter && !store.getters.isIntercept) {
try {
cancelRequest(config.url, cancel, "重复请求");
} catch (e) {
//
}
}
config.headers["X-Requested-With"] = "XMLHttpRequest";
if (
config.url.indexOf("/rmsApi/") >= 0 ||
config.url.indexOf("/api/") < 0
) {
config.withCredentials = false;
}
if (auth.getAuthorization()) {
config.headers["Authorization"] = auth.getAuthorization(); // 让每个请求携带自定义token 请根据实际情况自行修改
}
if (auth.getSystemUid()) {
config.headers["SystemUid"] = auth.getSystemUid(); // 让每个请求携带自定义token 请根据实际情况自行修改
} else {
console.error("SystemUid not find");
}
if (config.responseType != "arraybuffer") {
setTimeout(() => {
if (!loadingInstance) {
if (reqNum > 0) {
loadingInstance = Loading.service({
target: ".el-main",
fullscreen: false,
text: "数据请求中...",
background: "rgba(0,0,0,0.1)"
});
}
}
}, 500);
reqNum++;
}
// Do something before request is sent
// const token = auth.getToken()
// if (token) {
// config.headers['X-Access-Token'] = token // 让每个请求携带自定义 token 请根据实际情况自行修改
// }
if (config.method === "get") {
let params = config.params;
let Nparams = {};
for (let item in params) {
if (item.indexOf("like_") == 0) {
Nparams[item.replace("like_", "")] = "*" + params[item] + "*";
} else if (item.indexOf("left_like_") == 0) {
Nparams[item.replace("left_like_", "")] = params[item] + "*";
} else if (item.indexOf("right_like_") == 0) {
Nparams[item.replace("right_like_", "")] = "*" + params[item];
} else {
Nparams[item] = params[item];
}
}
config.params = Nparams;
if (config.url.indexOf("/round/pagelist") >= 0) {
config.params.column = config.params.column || "createTime"
config.params.order = config.params.order || "DESC"
}
// 中央督察、自治区督察,分别给所有接口加 systemType
// 整改管理两个督察类型分别在所有接口加 systemtype
// routertag为'zydc'时添加 systemType=1
var a = {
systemType: 1
}
var b = {
systemType: 2
}
if (store.getters.routerTag == 'zydc') {
config.params = Object.assign(config.params, a)
} else if (store.getters.routerTag == 'zzqdc') {
config.params = Object.assign(config.params, b)
} else if (store.getters.routerTag == 'zggl') {
if (store.getters.zgglSystemType == '1') {
config.params = Object.assign(config.params, a)
} else if (store.getters.zgglSystemType == '2') {
config.params = Object.assign(config.params, b)
}
}
}
return config;
},
error => {
reqNum++;
// Do something with request error
return Promise.reject(error);
}
);
// Add a response interceptor 响应拦截器
_axios.interceptors.response.use(
function (response) {
if (response.headers.sessionkey) {
store.commit('Set_sessionkey', response.headers.sessionkey);
}
closeLoading();
if (response.config.responseType == "arraybuffer") {
const fileName = response.headers.filename;
return Promise.resolve({
fileName: decodeURI(fileName),
data: response.data
})
}
// Do something with response data
if (!response.status >= 200 && !response.status < 300) {
notification.warning({
title: "系统提示",
message: response.data,
duration: 4000
});
return Promise.reject(response.data);
}
return response.data;
},
function (error) {
closeLoading();
// Do something with response error
return err(error);
//return Promise.reject(error);
}
);
import request from '@/utils/request'
export function login(data) {
return request({
url: '/vue-admin-template/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/vue-admin-template/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/vue-admin-template/user/logout',
method: 'post'
})
}
localStorage存储方式:很详细的一篇文章!vue实现token用户登录
Vue刷新token,判断token是否过期、失效的最简便的方法
结合 vuex 存储 token
在store文件的state中初始化token,因为state中的数据不支持直接修改,所以我们需要定义方法setToken(设置token)
和 getToken(获取token)
,然后我们就可以在登录接口处引入this.$store.commit('setToken',JSON.stringify(res.data.token))
,将后台传来的token存入Vuex和localStorage中
,为什么还要存入localStorage,Vuex中的状态一旦页面刷新就不再存在
,为了保持当前状态,需要通过localStorage中提取状态再传值给Vuex
。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token:'' //初始化token
},
mutations: {
//存储token方法
//设置token等于外部传递进来的值
setToken(state, token) {
state.token = token
localStorage.token = token //同步存储token至localStorage
},
},
getters : {
//获取token方法
//判断是否有token,如果没有重新赋值,返回给state的token
getToken(state) {
if (!state.token) {
state.token = localStorage.getItem('token')
}
return state.token
}
},
actions: {
}
})
github地址:https://github.com/js-cookie/js-cookie
https://www.npmjs.com/package/js-cookie
js-cookie中文文档
vue项目中js-cookie的使用存储token
NPM 安装
npm install --save js-cookie
src/utils/auth.js 引入 Cookies
import Cookies from 'js-cookie'
例子:
import Cookies from 'js-cookie'
const TokenKey = 'vue_admin_template_token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
MockJS快速入门
前后端分离,前端通过mock开发,无需等待后端接口开发好了再开发
npm install mockjs
移除 mock
在vue.config.js
中移除webpack-dev-server
中proxy
和after
这个Middleware就可以了。
proxy: {
// change xxx-api/login => mock/login
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:${port}/mock`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
}
}
},
after: require('./mock/mock-server.js')
mock-server
只会在开发环境中使用,线上生产环境目前使用MockJs
进行模拟。如果不需要请移除。具体代码:main.js
import { mockXHR } from '../mock'
if (process.env.NODE_ENV === 'production') {
mockXHR()
}
/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {
const { mockXHR } = require('../mock')
mockXHR()
}
修改
最常见的操作就是:你本地模拟了了一些数据,待后端完成接口后,逐步替换掉原先 mock 的接口。
我们以src/api/role.js中的getRoles接口为例。它原本是在mock/role/index.js中 mock 的数据。现在我们需要将它切换为真实后端数据,只要在mock/role/index.js找到对应的路由,之后将它删除即可。这时候你可以在network中,查看到真实的数据。
// api 中声明的路由
export function getRoles() {
return request({
url: '/roles',
method: 'get'
})
}
//找到对应的路由,并删除
{
url: '/roles',
type: 'get',
response: _ => {
return {
code: 20000,
data: roles
}
}
},
https://blog.csdn.net/qq_35844177/article/details/70171054
npm install --save nprogress
src/permission.js 中引入
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'