日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > vue >内容正文

vue

中大型Vue项目的前端架构-1

發(fā)布時(shí)間:2024/1/18 vue 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 中大型Vue项目的前端架构-1 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

?

前言

項(xiàng)目目錄

Api后端接口

公共Helper

sevice 網(wǎng)絡(luò)請(qǐng)求封裝(axios封裝)

utils工具類

main.js webpack入口文件

使用方法


前言

接觸Vue已經(jīng)有幾年了,每次新建項(xiàng)目都有一些新奇的想法,之前分享過(guò)一篇Vue中使用Axios攔截器(攔截請(qǐng)求與相應(yīng)),由于我最近的項(xiàng)目需要長(zhǎng)期維護(hù),所以不能再向小項(xiàng)目那種方式創(chuàng)建前端架構(gòu)了,需求需要方便維護(hù)、高擴(kuò)展性,但不是說(shuō)我最初的那種方式不好,只是不適合中大型項(xiàng)目而已。所以今天我分享一下我在中大型項(xiàng)目中封裝Axios和Helper的方法。每個(gè)人的需求不同,抱著學(xué)習(xí)的態(tài)度,大家一起分享經(jīng)驗(yàn)。所以廢話不多說(shuō),直接上干貨。

項(xiàng)目目錄

首先是我的項(xiàng)目架構(gòu),由于我的項(xiàng)目分的比較細(xì),我只展示部分和本文章相關(guān)的模塊。

|-----src | |-----common 公共文件 | | |-----Api 后端接口 | | | |-----modules 接口模塊 | | | | |-----User.js 用戶接口模塊 | | | |-----index.js 公共接口模塊 | | |-----Helper 公共Helper | | | |-----index.js 公共Helper | | | |-----.....js 其他公共方法抽離 | |-----sevice 網(wǎng)絡(luò)請(qǐng)求封裝(axios封裝) | | |-----api.js 請(qǐng)求方式封裝 | | |-----request.js axios封裝 | |-----utils 工具類 | | |-----vue-install.js vue全局綁定工具類 | |-----main.js webpack入口文件

Api后端接口

為什么要把接口單獨(dú)抽離出模塊呢?是因?yàn)樵谥写笮晚?xiàng)目中后端可能使用saas平臺(tái)架構(gòu),拆分出不同模塊,為了方便維護(hù),快速查找定位接口,我們就需要將單文件進(jìn)行解耦,抽離相同模塊方便維護(hù)。當(dāng)然如果后端沒(méi)有用saas平臺(tái)架構(gòu)或接口較少的話,可以不使用這種方式直接寫到index.js中這些都是根據(jù)個(gè)人需求去改變的無(wú)需糾結(jié)。

// index.js import User from './modules/User'export default {User, // 將獨(dú)立的模塊抽離到單獨(dú)的js文件中可以方便統(tǒng)一維護(hù)// 將公共的接口抽離出來(lái)方便維護(hù) method:請(qǐng)求方式 url:接口地址sendSms: { method: 'post', url: '' },uploadFile: { method: 'post', url: '' } } // User.js export default {getUser: {method: 'get', url: ''} }

公共Helper

同理,helper也可以抽離出不同的方法,方便維護(hù)。

// index.js import deepClone from './deepClone' import FormatDate from './FormatDate'const Helper = {/*** 深度拷貝* @param {object} 對(duì)象* @return {object}*/deepClone,/*** 日期格式化* @param {date} timestamp 日期/時(shí)間戳* @param {string} format 格式 默認(rèn)值 Y-m-d* @return {string}*/FormatDate,/*** 獲取指定日期之間的所有日期* 日期格式 yyyy-MM-dd* @param {string} start 開(kāi)始日期* @param {string} start 結(jié)束日期* @return {array}*/getAllDate,/*** 隨機(jī)字符串* @param {boolean} lower 小寫字母* @param {boolean} upper 大寫字母* @param {boolean} number 數(shù)字* @param {boolean} symbol 特殊字符* @param {boolean} length 長(zhǎng)度*/RandomString,/*** 計(jì)算請(qǐng)求分頁(yè)參數(shù)* @param {object} route 當(dāng)前頁(yè)面路由* @return { limit: 10, page: 1, offset: 0 } limit = 長(zhǎng)度, page = 頁(yè)碼, offset = 偏移量*/getPerPage (query) {let limit = parseInt(query.limit) || 10,page = parseInt(query.page) || 1,offset = (page - 1) * limit;return {limit, page, offset}},/*** 清理對(duì)象* 去除屬性值為 空(字符串), null, undefined* 轉(zhuǎn)換值為數(shù)字,true,false的字符串為對(duì)應(yīng)的數(shù)據(jù)類型* @param {object} obj 對(duì)象* @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();// 過(guò)濾空值if (v.length === 0) continue;// 正數(shù),負(fù)數(shù),浮點(diǎn)數(shù)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;

由于有些代碼比較長(zhǎng)我這里只分享一部分模塊。

// 深度復(fù)制 const deepClone = (obj) => {let o;if (typeof obj === 'object') {if (obj === null) {o = null} else {// 數(shù)組if (obj instanceof Array) {o = [];for (const item of obj) {o.push(deepClone(item))}}// 對(duì)象else {o = {};for (const j in obj) {o[j] = deepClone(obj[j])}}}}else {o = obj;}return o; }export default deepClone;

到此我的common公共文件就完成了,其實(shí)中心思想還是將之前的單文件抽離出不同的模塊,這樣方便后面擴(kuò)展。接下來(lái)是網(wǎng)絡(luò)請(qǐng)求的封裝。這里可能比較繞,不過(guò)仔細(xì)看過(guò)后還是能理解的。

sevice 網(wǎng)絡(luò)請(qǐng)求封裝(axios封裝)

// api.js import Api from '@/common/Api' import Helper from '@/common/Helper' import axios from './request'const axiosApi = {// get請(qǐng)求createGet (url) {return (args = {}) => {return axios({method: 'GET',url: url,...args})}},// post請(qǐng)求createPost (url) {return (args = {}) => {let parmas = ''/*不掛載到url地址上 為什么我這里要這么寫呢,因?yàn)楹蠖藀ost接收參數(shù)有一部分是從地址欄獲取,雖然我很詫異但是我直接給他兩份他隨便獲取,當(dāng)然可以根據(jù)notMountUrl參數(shù)選擇不綁定到地址欄*/ if (!args.notMountUrl) {parmas = `?${Helper.formatParams(args.data)}`;}return axios({method: 'POST',url: `${url}${parmas}`,...args})}}, // .... 當(dāng)然你也可以寫更多請(qǐng)求方式或者根據(jù)不同的需求調(diào)用不同的Axios封裝// 創(chuàng)建API請(qǐng)求方法crateApi (apiConfig) {let methods = {}// 獲取所有api的Key值進(jìn)行循環(huán)Object.keys(apiConfig).forEach(key => {let item = apiConfig[key]// 子集請(qǐng)求 判斷是否是單獨(dú)模塊 如果是就遞歸子集if (!item.method && !item.url) {return methods[key] = this.crateApi(item)}// 接口動(dòng)態(tài)創(chuàng)建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} } // 這里一定是拋出創(chuàng)建方法,如果你暈了可以從這一步往回走,慢慢你就懂了 export default axiosApi.crateApi(Api) // request.js import axios from 'axios' // 這里我使用的是vant ui庫(kù)可根據(jù)需求更換不同的ui庫(kù) import { Toast } from 'vant'; import store from '@/store' import router from '@/router' // statusCode 錯(cuò)誤狀態(tài)碼 這里錯(cuò)誤碼其實(shí)就是將網(wǎng)絡(luò)請(qǐng)求中的所有status進(jìn)行了鍵值對(duì)的封裝方便調(diào)用 import statusCode from '@/common/BaseData/status_code.js'// 是否為生產(chǎn)環(huán)境 const isProduction = process.env.NODE_ENV == "production";// 創(chuàng)建一個(gè)axios實(shí)例 const service = axios.create({baseURL: !isProduction ? '/api' : process.env.VUE_APP_BASE_URL, // 前綴由于我使用的是webpack的全局變量,這里其實(shí)也可以寫死withCredentials: true, // 當(dāng)跨域請(qǐng)求時(shí)發(fā)送cookietimeout: 20000 // 請(qǐng)求超時(shí)時(shí)間 })// 請(qǐng)求攔截器 service.interceptors.request.use(config => {// 獲取tokenconst hasToken = store.getters.Token// 設(shè)置 token設(shè)置tokenif (hasToken) {config.headers['token'] = hasToken}// .... 其他操作根據(jù)具體需求增加return config},error => {// 處理請(qǐng)求錯(cuò)誤// console.log(error)return Promise.reject(error)} )// 響應(yīng)攔截器 service.interceptors.response.use(/*** 通過(guò)自定義代碼確定請(qǐng)求狀態(tài)*/response => {const res = response.data// 這里的error是后臺(tái)返回給我的固定數(shù)據(jù)格式 可根據(jù)后端返回?cái)?shù)據(jù)自行修改const { error } = res;// error不為nullif (error) {// 彈出報(bào)錯(cuò)信息Toast.fail({icon: 'failure',message: error.msg})// 后端返回code的報(bào)錯(cuò)處理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:// 如果狀態(tài)碼不是 則判斷為報(bào)錯(cuò)信息return Promise.reject(new Error(error.msg))}} else {// 正常返回return res}},error => {// 這里就是status網(wǎng)絡(luò)請(qǐng)求的報(bào)錯(cuò)處理 主要處理300+ 400+ 500+的狀態(tài)console.error('err:' + error)// 彈出請(qǐng)求報(bào)錯(cuò)信息Toast(statusCode[error.statusCode])return Promise.reject(error)} ) // 向外拋出 export default service

service網(wǎng)絡(luò)請(qǐng)求封裝結(jié)束,這里主要的是api.js的封裝比較繞,其實(shí)就是動(dòng)態(tài)創(chuàng)建后端接口的方法,萬(wàn)變不離其宗,都是換湯不換藥的寫法

utils工具類

最后的工具類其實(shí)就是將我們所有的方法綁定到vue的prototype原型上,以此形成完整的閉環(huán) 如果不了解vue綁定插件的機(jī)制的話,可以去vue.js官網(wǎng)自行查找,其實(shí)沒(méi)多難。

// vue-install.js 全局綁定 import Api from '@/service/api' import Helper from '@/common/Helper'export default {install: (Vue) => {// 全局注入 $api 請(qǐng)求 將我們api.js拋出的方法綁定到vue實(shí)例上Vue.prototype.$api = Api// 全局注入 $helper 輔助方法 同理將helper公共方法綁定到vue上Vue.prototype.$helper = Helper} }

工具類的綁定結(jié)束,致辭我們就差最后一步就完成我們的閉環(huán)了,那就是引入到main.js中

main.js webpack入口文件

import Vue from 'vue'import router from './router' import store from './store' // .... 其他依賴引入 import vueInstall from './utils/vue-install' // 全局注冊(cè)// 全局綁定 直接使用use方法綁定 Vue.use(vueInstall);new Vue({router,store,render: h => h(App) }).$mount('#app')

使用方法

// 某頁(yè)面 async created () {// 請(qǐng)求User模塊const res = await this.$api.User.getUser({ data: { // 參數(shù).....},// 選擇是否掛載到url上 notMountUrl: false})// 深拷貝const newResult = this.$helper.deepClone(this.result)}

大功告成,這就是目前我項(xiàng)目中網(wǎng)絡(luò)請(qǐng)求與helper公共方法的封裝。希望對(duì)大家有所幫助,同時(shí)也虛心接受大家的各種建議和意見(jiàn)。希望大家在評(píng)論區(qū)進(jìn)行評(píng)論。我會(huì)持續(xù)對(duì)我所掌握的知識(shí)進(jìn)行分享。不忘初心堅(jiān)持開(kāi)源開(kāi)放的學(xué)習(xí)態(tài)度。

總結(jié)

以上是生活随笔為你收集整理的中大型Vue项目的前端架构-1的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。