文章目錄
-
- 移動端
- pc端
- 建構項目
- 我的步驟
-
- 示例一:vue init webpack 檔案名
- 示例二:vue create 檔案名
- vue.config.js 配置
- ui架構包
- 安裝異步程式設計架構axios
- 關于前端登入存儲 token
- js-cookie
- 安裝mock
- 在vue項目中使用Nprogress.js進度條
vue-cli
安裝 ui 庫(eg:pc端用element ui、移動端用 vuex)
移動端
vux
github位址
pc端
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 init webpack 檔案名
vue init webpack 檔案名
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPB5UNjpnTzcmeOpHOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL0QTYwITMiF2NzczN1IWOiRTN1QjZ5QGOjNzYwQGM3Q2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
示例二:vue create 檔案名
參考:超級詳細的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就足夠了。
vue.config.js 配置
module.exports = {
devServer: {
// 端口号
port: 8080,
// 配置不同的背景API位址
proxy: {
'/api': {
target: 'http://www.dzm.com',
ws: false,
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
ui架構包
element-ui官網:http://element-cn.eleme.io/#/zh-CN/component/installation
npm 安裝
完整引入
在 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中文文檔|axios中文網:http://www.axios-js.com/zh-cn/docs/
vue項目中axios攔截器的使用和配置
- 安裝_使用 npm:
npm install axios
- src/utils/request.js 中引入 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);
}
);
- 在 src/api/下的 js 檔案引入 axios 執行個體,然後寫各種請求方法
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'
})
}
關于前端登入存儲 token
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: {
}
})
js-cookie
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'
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)
}
安裝mock
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
}
}
},
在vue項目中使用Nprogress.js進度條
https://blog.csdn.net/qq_35844177/article/details/70171054
npm install --save nprogress
src/permission.js 中引入
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'