摘要:公司做的大部分都是后臺(tái)管理項(xiàng)目,剔除每個(gè)項(xiàng)目的業(yè)務(wù)邏輯,其實(shí)都可以用通用的一套模版來(lái)做。總結(jié)以上都是后臺(tái)系統(tǒng)中可以用到的一些處理方式,具體代碼可查看。其他總結(jié)文章常規(guī)打包優(yōu)化方案組件通信處理方案
公司做的大部分都是后臺(tái)管理項(xiàng)目,剔除每個(gè)項(xiàng)目的業(yè)務(wù)邏輯,其實(shí)都可以用通用的一套模版來(lái)做。
登錄邏輯每個(gè)系統(tǒng)都有自己的登錄登出邏輯,而我們前端所要做的其實(shí)是請(qǐng)求后臺(tái),拿到登錄權(quán)限,帶上登錄權(quán)限,獲取用戶(hù)信息和菜單信息。
在vue項(xiàng)目開(kāi)發(fā)當(dāng)中,我們一般都是在全局路由鉤子做這一系列判斷。
router.beforeEach(async(to, from, next) => { NProgress.start(); await store.dispatch("SetConfigApi"); // 獲取配置 await store.dispatch("SetApi"); // 設(shè)置基本配置 const token = await store.dispatch("getToken"); // 獲取token if (token) { // 用戶(hù)信息不存在 if (!store.getters.userInfo) { await store.dispatch("GetUser"); // 獲取用戶(hù)信息 const menuList = await store.dispatch("GetMenu", localRoute); // 獲取菜單 await store.dispatch("GenerateRoutes", localRoute); router.addRoutes(store.getters.addRoutes); ... } else { next(); } } else { if (whiteList.includes(to.path)) { // 在免登錄白名單,直接進(jìn)入 next(); } else { window.location.href = store.getters.api.IPORTAL_LOCAL_API; NProgress.done(); } } });
當(dāng)用戶(hù)進(jìn)入系統(tǒng)的時(shí)候,先獲取系統(tǒng)的配置信息,這個(gè)配置信息可以是前端json文件,或者是后臺(tái)接口;用這種方式可以靈活的修改項(xiàng)目中的配置,而不用每次都打包死進(jìn)入項(xiàng)目,直接可以要運(yùn)維童靴修改對(duì)應(yīng)的配置信息,就可以了。
菜單權(quán)限以前的菜單路由是直接寫(xiě)死在前端,但是當(dāng)我們直接訪問(wèn)這個(gè)路由時(shí),用戶(hù)還是可以進(jìn)入到這個(gè)功能頁(yè)面;后來(lái)直接改成動(dòng)態(tài)添加路由的方式router.addRoutes。
前端先獲取菜單列表
根據(jù)獲取的菜單列表循環(huán)添加用戶(hù)菜單路由集合
動(dòng)態(tài)添加路由
具體可查看
請(qǐng)求方案項(xiàng)目請(qǐng)求是使用的axios,可以對(duì)它添加攔截器來(lái)處理我們的請(qǐng)求,也可以處理通過(guò)axios.CancelToken重復(fù)請(qǐng)求,具體可看代碼:
// 設(shè)置請(qǐng)求統(tǒng)一信息 import axios from "axios"; import store from "@/store/index.js"; import qs from "qs"; import { messages } from "./msg-box.js"; const service = axios.create({ timeout: 300000, // 超時(shí)設(shè)置 withCredentials: true // 跨域請(qǐng)求 }); let hasLogoutStatus = false; // 是否某個(gè)請(qǐng)求存在需要退出的狀態(tài) const queue = []; // 請(qǐng)求隊(duì)列 const CancelToken = axios.CancelToken; // axios內(nèi)置的中斷方法 /** * 拼接請(qǐng)求的url和方法; * 同樣的`url + method` 可以視為相同的請(qǐng)求 * @param {Object} config 請(qǐng)求頭對(duì)象 */ const token = config => { return `${config.url}_${config.method}`; }; /** * 中斷重復(fù)的請(qǐng)求,并從隊(duì)列中移除 * @param {Object} config 請(qǐng)求頭對(duì)象 */ const removeQueue = config => { for (let i = 0, size = queue.length; i < size; i++) { const task = queue[i]; if (!task) return; // 出現(xiàn)401,403狀態(tài)碼中斷后續(xù)請(qǐng)求 const isLogout = token(config).includes("logout"); // 退出接口跳過(guò)中斷邏輯 if (!isLogout && hasLogoutStatus) { task.token(); queue.splice(i, 1); } else { const cancelMethods = ["post", "put", "delete"]; // 需要中斷的請(qǐng)求方式 const { method } = config; if (cancelMethods.includes(method)) { if (task.token === token(config)) { task.cancel(); queue.splice(i, 1); } } } } }; /** * 請(qǐng)求錯(cuò)誤統(tǒng)一處理 * @param {Object} response 錯(cuò)誤對(duì)象 */ const errorHandle = response => { // eslint-disable-next-line prettier/prettier const { status, data: { message = "" }} = response; let msg = message; if (!message) { switch (status) { case 401: msg = "您沒(méi)有權(quán)限訪問(wèn)此操作!"; break; case 403: msg = "您的登錄狀態(tài)已失效,請(qǐng)重新登錄。"; break; case 424: msg = response.data.error; break; default: msg = "服務(wù)請(qǐng)求異常,請(qǐng)刷新重試。"; } } hasLogoutStatus = status === 401 || status === 403; if (hasLogoutStatus) { messages("error", msg, () => { store.dispatch("Logout"); }); } messages("error", msg); }; // 請(qǐng)求攔截器 service.interceptors.request.use( config => { // 中斷之前的同名請(qǐng)求 removeQueue(config); // 添加cancelToken config.cancelToken = new CancelToken(c => { queue.push({ token: token(config), cancel: c }); }); // 登錄后添加token if (store.getters.token) { config.headers["Authorization"] = store.getters.token.token_type + " " + store.getters.token.access_token; } return config; }, error => { return Promise.reject(error); } ); // 響應(yīng)攔截器 service.interceptors.response.use( response => { // 在請(qǐng)求完成后,自動(dòng)移出隊(duì)列 removeQueue(response.config); // 關(guān)閉全局按鈕Loading響應(yīng) store.dispatch("CancalLoading"); // 錯(cuò)誤碼處理 if (response.status !== 200) { return Promise.reject(response); } return response; }, error => { const { response } = error; if (response) { // 錯(cuò)誤處理 errorHandle(response); return Promise.reject(response); } else { // 請(qǐng)求超時(shí) if (error.message.includes("timeout")) { console.log("超時(shí)了"); messages("error", "請(qǐng)求已超時(shí),請(qǐng)刷新或檢查互聯(lián)網(wǎng)連接"); } else { // 斷網(wǎng),可以展示斷網(wǎng)組件 console.log("斷網(wǎng)了"); messages("error", "請(qǐng)檢查網(wǎng)絡(luò)是否已連接"); } } } ); export default { get: (url, data = {}) => { return new Promise((resolve, reject) => { service .get(store.getters.api.API + url, { params: data }) .then(response => { resolve(response.data); }) .catch(error => { reject(error); }); }).catch(error => { throw new Error(error); }); }, post: (url, data = {}) => { return new Promise((resolve, reject) => { service .post(store.getters.api.API + url, data, { headers: { "Content-Type": "application/x-www-form-urlencoded;charset=utf-8" }, withCredentials: true, transformRequest: [ data => { return qs.stringify(data); } ] }) .then(response => { resolve(response.data); }) .catch(error => { reject(error); }); }).catch(error => { return Promise.reject(error); }); }, ... /** * blob下載 * @param {String} url 請(qǐng)求地址 * @param {String} method 請(qǐng)求方式 默認(rèn)`get` * @param {Object} data 請(qǐng)求數(shù)據(jù) */ exportFile({ url = "", data = {}, method = "get" }) { return new Promise((resolve, reject) => { const isPost = method.toLocaleUpperCase() === "POST" ? { headers: { "Content-Type": "application/json" }, data } : { params: data }; const downConfig = { withCredentials: true, responseType: "blob", ...isPost }; service // eslint-disable-next-line no-unexpected-multiline [method](store.getters.api.API + url, downConfig) .then(response => { resolve(response); }) .catch(error => { reject(error); }); }).catch(error => { return Promise.reject(error); }); } };
當(dāng)需要使用請(qǐng)求時(shí),可以引用文件http.js,也可以掛在到vue原型上,在組件內(nèi)使用this.$http
// user.js import http from "@/utils/http.js"; export function getUser() { return http.get("/user"); } // main.js Vue.prototype.$http = http;按鈕Loading處理
按鈕的loading效果可以處理后臺(tái)響應(yīng)時(shí)間有點(diǎn)長(zhǎng)場(chǎng)景,這里使用store封裝了下處理方式。
// loading.js import Vue from "vue"; const loading = { state: {}, mutations: { SET_LOADING: (state, data) => { const isObject = Object.prototype.toString.call(data) === "[object Object]"; if (!isObject) return; Object.keys(data).forEach(key => { Vue.set(state, key, data[key]); }); }, CANCAL_LOADING: state => { Object.keys(state).forEach(key => { Vue.delete(state, key); }); } }, actions: { SetLoading({ commit }, data) { commit("SET_LOADING", data); }, CancalLoading({ commit }, data) { commit("CANCAL_LOADING", data); } } }; export default loading; // http.js service.interceptors.response.use( response => { // 關(guān)閉全局按鈕Loading響應(yīng) store.dispatch("CancalLoading"); ... })
在組件內(nèi)定義
保存 computed: { btn() { return this.$store.state.loading; } } methods: { handleClick() { this.$store.dispatch("SetLoading", { save: true }); } }
以上就可以完美的使用loading,而不用每個(gè)都在data中定義了。
總結(jié)以上都是后臺(tái)系統(tǒng)中可以用到的一些處理方式,具體代碼可查看。
其他總結(jié)文章:
webpack常規(guī)打包優(yōu)化方案
組件通信處理方案
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/104839.html
摘要:項(xiàng)目開(kāi)發(fā)完成,接下來(lái)是上線,關(guān)于項(xiàng)目的部署,我司前端是部署在服務(wù)器上,關(guān)于的相關(guān)文檔,請(qǐng)自行查閱本文只記錄部署時(shí)碰到的一些問(wèn)題。其他總結(jié)文章常規(guī)打包優(yōu)化方案組件通信處理方案后臺(tái)管理項(xiàng)目總結(jié) 項(xiàng)目開(kāi)發(fā)完成,接下來(lái)是上線,關(guān)于vue項(xiàng)目的部署,我司前端是部署在nginx服務(wù)器上,關(guān)于nginx的相關(guān)文檔,請(qǐng)自行查閱;本文只記錄部署時(shí)碰到的一些問(wèn)題。 打包 vue項(xiàng)目打包后,是生成一系列的靜...
摘要:項(xiàng)目中,組件是項(xiàng)目的基石,每個(gè)頁(yè)面都是組件來(lái)組裝起來(lái),我司沒(méi)有自己的組件庫(kù),選用的是組件庫(kù),在它的基礎(chǔ)上再次封裝。部分代碼三級(jí)效果如下總結(jié)組件是項(xiàng)目的積木條,公用組件的封裝成功與否其實(shí)是對(duì)項(xiàng)目的開(kāi)發(fā)效率有直接影響。 vue項(xiàng)目中,組件是項(xiàng)目的基石,每個(gè)頁(yè)面都是組件來(lái)組裝起來(lái),我司沒(méi)有自己的組件庫(kù),選用的是ElementUI組件庫(kù),在它的基礎(chǔ)上再次封裝。 可編輯表格 由于是后臺(tái)管理項(xiàng)目,...
摘要:導(dǎo)語(yǔ)承接上文實(shí)戰(zhàn)之后臺(tái)管理系統(tǒng)開(kāi)發(fā)一在上一篇文章中,我詳細(xì)敘述了如何創(chuàng)建項(xiàng)目框架和引入各種后臺(tái)常用插件,做好這些準(zhǔn)備工作后,我們就可以著手進(jìn)行頁(yè)面的開(kāi)發(fā)了。如果傳入的數(shù)據(jù)不符合規(guī)格,會(huì)發(fā)出警告。 1. 導(dǎo)語(yǔ) 承接上文:Vue 2.x 實(shí)戰(zhàn)之后臺(tái)管理系統(tǒng)開(kāi)發(fā)(一) 在上一篇文章中,我詳細(xì)敘述了如何創(chuàng)建項(xiàng)目框架和引入各種后臺(tái)常用插件,做好這些準(zhǔn)備工作后,我們就可以著手進(jìn)行頁(yè)面的開(kāi)發(fā)了。在開(kāi)...
閱讀 3621·2021-09-30 09:59
閱讀 2229·2021-09-13 10:34
閱讀 576·2019-08-30 12:58
閱讀 1507·2019-08-29 18:42
閱讀 2198·2019-08-26 13:44
閱讀 2922·2019-08-23 18:12
閱讀 3321·2019-08-23 15:10
閱讀 1625·2019-08-23 14:37