中大型Vue项目的前端架构-1
目錄
?
前言
項目目錄
Api后端接口
公共Helper
sevice 網絡請求封裝(axios封裝)
utils工具類
main.js webpack入口文件
使用方法
前言
接觸Vue已經有幾年了,每次新建項目都有一些新奇的想法,之前分享過一篇Vue中使用Axios攔截器(攔截請求與相應),由于我最近的項目需要長期維護,所以不能再向小項目那種方式創建前端架構了,需求需要方便維護、高擴展性,但不是說我最初的那種方式不好,只是不適合中大型項目而已。所以今天我分享一下我在中大型項目中封裝Axios和Helper的方法。每個人的需求不同,抱著學習的態度,大家一起分享經驗。所以廢話不多說,直接上干貨。
項目目錄
首先是我的項目架構,由于我的項目分的比較細,我只展示部分和本文章相關的模塊。
|-----src | |-----common 公共文件 | | |-----Api 后端接口 | | | |-----modules 接口模塊 | | | | |-----User.js 用戶接口模塊 | | | |-----index.js 公共接口模塊 | | |-----Helper 公共Helper | | | |-----index.js 公共Helper | | | |-----.....js 其他公共方法抽離 | |-----sevice 網絡請求封裝(axios封裝) | | |-----api.js 請求方式封裝 | | |-----request.js axios封裝 | |-----utils 工具類 | | |-----vue-install.js vue全局綁定工具類 | |-----main.js webpack入口文件Api后端接口
為什么要把接口單獨抽離出模塊呢?是因為在中大型項目中后端可能使用saas平臺架構,拆分出不同模塊,為了方便維護,快速查找定位接口,我們就需要將單文件進行解耦,抽離相同模塊方便維護。當然如果后端沒有用saas平臺架構或接口較少的話,可以不使用這種方式直接寫到index.js中這些都是根據個人需求去改變的無需糾結。
// index.js import User from './modules/User'export default {User, // 將獨立的模塊抽離到單獨的js文件中可以方便統一維護// 將公共的接口抽離出來方便維護 method:請求方式 url:接口地址sendSms: { method: 'post', url: '' },uploadFile: { method: 'post', url: '' } } // User.js export default {getUser: {method: 'get', url: ''} }公共Helper
同理,helper也可以抽離出不同的方法,方便維護。
// index.js import deepClone from './deepClone' import FormatDate from './FormatDate'const Helper = {/*** 深度拷貝* @param {object} 對象* @return {object}*/deepClone,/*** 日期格式化* @param {date} timestamp 日期/時間戳* @param {string} format 格式 默認值 Y-m-d* @return {string}*/FormatDate,/*** 獲取指定日期之間的所有日期* 日期格式 yyyy-MM-dd* @param {string} start 開始日期* @param {string} start 結束日期* @return {array}*/getAllDate,/*** 隨機字符串* @param {boolean} lower 小寫字母* @param {boolean} upper 大寫字母* @param {boolean} number 數字* @param {boolean} symbol 特殊字符* @param {boolean} length 長度*/RandomString,/*** 計算請求分頁參數* @param {object} route 當前頁面路由* @return { limit: 10, page: 1, offset: 0 } limit = 長度, page = 頁碼, offset = 偏移量*/getPerPage (query) {let limit = parseInt(query.limit) || 10,page = parseInt(query.page) || 1,offset = (page - 1) * limit;return {limit, page, offset}},/*** 清理對象* 去除屬性值為 空(字符串), null, undefined* 轉換值為數字,true,false的字符串為對應的數據類型* @param {object} obj 對象* @return {object}*/clearObject (obj) {let o = {};for (const k in obj) {let v = obj[k];if (v === null || v === undefined) continue;// 非字符串if (toString.call(v) !== '[object String]') {o[k] = v;continue;}v = obj[k].trim();// 過濾空值if (v.length === 0) continue;// 正數,負數,浮點數if (/^(-?\d+)(\.\d+)?$/.test(v)) {o[k] = Number(v);}// 布爾值else if (v === 'true' || v === 'false') {o[k] = (v === 'true');}// falseelse {o[k] = v;}}return o;}}export default Helper;由于有些代碼比較長我這里只分享一部分模塊。
// 深度復制 const deepClone = (obj) => {let o;if (typeof obj === 'object') {if (obj === null) {o = null} else {// 數組if (obj instanceof Array) {o = [];for (const item of obj) {o.push(deepClone(item))}}// 對象else {o = {};for (const j in obj) {o[j] = deepClone(obj[j])}}}}else {o = obj;}return o; }export default deepClone;到此我的common公共文件就完成了,其實中心思想還是將之前的單文件抽離出不同的模塊,這樣方便后面擴展。接下來是網絡請求的封裝。這里可能比較繞,不過仔細看過后還是能理解的。
sevice 網絡請求封裝(axios封裝)
// api.js import Api from '@/common/Api' import Helper from '@/common/Helper' import axios from './request'const axiosApi = {// get請求createGet (url) {return (args = {}) => {return axios({method: 'GET',url: url,...args})}},// post請求createPost (url) {return (args = {}) => {let parmas = ''/*不掛載到url地址上 為什么我這里要這么寫呢,因為后端post接收參數有一部分是從地址欄獲取,雖然我很詫異但是我直接給他兩份他隨便獲取,當然可以根據notMountUrl參數選擇不綁定到地址欄*/ if (!args.notMountUrl) {parmas = `?${Helper.formatParams(args.data)}`;}return axios({method: 'POST',url: `${url}${parmas}`,...args})}}, // .... 當然你也可以寫更多請求方式或者根據不同的需求調用不同的Axios封裝// 創建API請求方法crateApi (apiConfig) {let methods = {}// 獲取所有api的Key值進行循環Object.keys(apiConfig).forEach(key => {let item = apiConfig[key]// 子集請求 判斷是否是單獨模塊 如果是就遞歸子集if (!item.method && !item.url) {return methods[key] = this.crateApi(item)}// 接口動態創建const method = item.method.toLocaleUpperCase()if (method === 'GET') {methods[key] = this.createGet(item.url)}else if (method === 'POST') {methods[key] = this.createPost(item.url)}})return methods} } // 這里一定是拋出創建方法,如果你暈了可以從這一步往回走,慢慢你就懂了 export default axiosApi.crateApi(Api) // request.js import axios from 'axios' // 這里我使用的是vant ui庫可根據需求更換不同的ui庫 import { Toast } from 'vant'; import store from '@/store' import router from '@/router' // statusCode 錯誤狀態碼 這里錯誤碼其實就是將網絡請求中的所有status進行了鍵值對的封裝方便調用 import statusCode from '@/common/BaseData/status_code.js'// 是否為生產環境 const isProduction = process.env.NODE_ENV == "production";// 創建一個axios實例 const service = axios.create({baseURL: !isProduction ? '/api' : process.env.VUE_APP_BASE_URL, // 前綴由于我使用的是webpack的全局變量,這里其實也可以寫死withCredentials: true, // 當跨域請求時發送cookietimeout: 20000 // 請求超時時間 })// 請求攔截器 service.interceptors.request.use(config => {// 獲取tokenconst hasToken = store.getters.Token// 設置 token設置tokenif (hasToken) {config.headers['token'] = hasToken}// .... 其他操作根據具體需求增加return config},error => {// 處理請求錯誤// console.log(error)return Promise.reject(error)} )// 響應攔截器 service.interceptors.response.use(/*** 通過自定義代碼確定請求狀態*/response => {const res = response.data// 這里的error是后臺返回給我的固定數據格式 可根據后端返回數據自行修改const { error } = res;// error不為nullif (error) {// 彈出報錯信息Toast.fail({icon: 'failure',message: error.msg})// 后端返回code的報錯處理switch (error.code) {case '1000':case '1001':case '1002':case '1003':router.replace({ path: '/error', query: { code: error.code, msg: error.msg } })break;case '6000':case '6100':// 清空Token 重新登錄store.dispatch('user/resetToken')return Promise.reject(new Error(error.msg));case '6200':case '7000':case '19000':default:// 如果狀態碼不是 則判斷為報錯信息return Promise.reject(new Error(error.msg))}} else {// 正常返回return res}},error => {// 這里就是status網絡請求的報錯處理 主要處理300+ 400+ 500+的狀態console.error('err:' + error)// 彈出請求報錯信息Toast(statusCode[error.statusCode])return Promise.reject(error)} ) // 向外拋出 export default serviceservice網絡請求封裝結束,這里主要的是api.js的封裝比較繞,其實就是動態創建后端接口的方法,萬變不離其宗,都是換湯不換藥的寫法
utils工具類
最后的工具類其實就是將我們所有的方法綁定到vue的prototype原型上,以此形成完整的閉環 如果不了解vue綁定插件的機制的話,可以去vue.js官網自行查找,其實沒多難。
// vue-install.js 全局綁定 import Api from '@/service/api' import Helper from '@/common/Helper'export default {install: (Vue) => {// 全局注入 $api 請求 將我們api.js拋出的方法綁定到vue實例上Vue.prototype.$api = Api// 全局注入 $helper 輔助方法 同理將helper公共方法綁定到vue上Vue.prototype.$helper = Helper} }工具類的綁定結束,致辭我們就差最后一步就完成我們的閉環了,那就是引入到main.js中
main.js webpack入口文件
import Vue from 'vue'import router from './router' import store from './store' // .... 其他依賴引入 import vueInstall from './utils/vue-install' // 全局注冊// 全局綁定 直接使用use方法綁定 Vue.use(vueInstall);new Vue({router,store,render: h => h(App) }).$mount('#app')使用方法
// 某頁面 async created () {// 請求User模塊const res = await this.$api.User.getUser({ data: { // 參數.....},// 選擇是否掛載到url上 notMountUrl: false})// 深拷貝const newResult = this.$helper.deepClone(this.result)}大功告成,這就是目前我項目中網絡請求與helper公共方法的封裝。希望對大家有所幫助,同時也虛心接受大家的各種建議和意見。希望大家在評論區進行評論。我會持續對我所掌握的知識進行分享。不忘初心堅持開源開放的學習態度。
總結
以上是生活随笔為你收集整理的中大型Vue项目的前端架构-1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 男生宿舍“卧谈”经典
- 下一篇: Java“长征”路起航