Vue專案架構優化

帕尼尼發表於2019-03-13

寫在前面

這篇部落格我將為你介紹vue的架構思想,當然這只是我根據遇到的專案總結的vue架構,這是我發現的一個小三輪,如果你有好的架構也歡迎指教哦。

好了,我們開始聊吧!

以我手擼的一個小專案 低配餓了麼外賣平臺 為例:線上演示地址

2019.4.14 最近一次重構git地址

最初的版本

目錄結構

├── src                // 生產目錄
│   ├── api            // axios操作
│   ├── components     // 元件 
│   │		├── common  // 公共元件
│   │		├── admin   // 使用者元件
│   │		└── seller  // 商家元件  		
│   ├── router         // 路由
│   ├── store          // vuex狀態管理器
│	├── App.vue        // 首頁
│   └── main.js        // Webpack 預編譯入口 
複製程式碼

程式碼邏輯

很簡單先訪問App.vue,根據路由對映不同元件渲染頁面,每個頁面都有ajax請求

ajax請求長這樣

getUserInfo: function() {
    this.axios.get('user/infor')
    .then(res => {
        if (res.data.status) {
            this.user = res.data.data;
        }
    })
    .catch(error => {
        console.log(error);
    });
},
複製程式碼

前端第一次重構

2018.4.21 Github地址:elm1.0

目錄結構

├── src                // 生產目錄
│   ├── api            // axios操作
│   ├── components     // 元件 
│   ├── router         // 路由
│   ├── store          // vuex狀態管理器
│	├── App.vue        // 首頁
│   └── main.js        // Webpack 預編譯入口
複製程式碼

沒錯只是將ajax請求都集中到了api目錄下 api目錄下的index.js檔案

import axios from 'axios';
import store from '../store';

let httpURL = "http://www.xuguobin.club/api/elm/" //這是我伺服器的api介面
let localURL = 'http://localhost/api/elm/';     //這是本地koa2的api介面
axios.defaults.baseURL = localURL;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

export default {
    //獲取使用者資訊
    getUser() {
        return axios.get('user/infor');
    },
    //獲取訂單
    getOrders(orderType) {
        return axios.get('user/order?type=' + orderType);
    },
    //提交訂單
    submitOrder(order) {
        return axios.get('user/submit?order=' + order);
    },
    //確認收貨
    confirmOrder(orderId) {
        return axios.get('user/confirm?orderId=' + orderId);
    },
    //提交評價
    submitRating(rating) {
        return axios.get('user/rating?rating=' + rating);
    },
    //使用者登入
    userLogin(user) {
        return axios.post('user/login',`username=${user.username}&password=${user.password}`);
    },
};
複製程式碼

這樣子做,很好的將axios請求與vue頁面解耦和了! 現在ajax請求長這樣

getUserInfo: function() {
    this.api.getUser()
    .then(res => {
        if (res.data.status) {
            this.user = res.data.data;
        }
    })
    .catch(error => {
        console.log(error);
    });
},
複製程式碼

前端第二次重構

2018.7.8 Github地址:elm2.0

目錄結構

講道理這次重構的有點過分

├── src                // 生產目錄
│   └── axios           // axios操作
|         ├──base       // axios模板
|         |    ├──base.js     //axios基類
|         |    └──setting.js  //狀態碼
|         └── user
|               ├──cache.js     //請求函式
|               └──config.js    //配置資訊
|
|   ├── base           //vue模板
│   ├── components     // 元件
|   |     ├──common    //公共元件
|   |     └──admin
|   |          ├── ui.vue             // 輸出元件
|   |          ├── component.html     // template
|   |          ├── component.js       // script
|   |          └── component.less     // style
|   |  
│   ├── router         // 路由
│   ├── store          // vuex狀態管理器
│	├── App.vue        // 首頁
│   └── main.js        // Webpack 預編譯入口
複製程式碼

第一次的重構雖然已經將axios請求和頁面分離開來了,但是每次請求後都要驗證狀態碼,處理錯誤資訊。

其實這完全沒有必要每個頁面都來一下,這些公共操作可以一起放在axios的基類

import axios from 'axios'
import setting from './setting'

let httpURL = "http://www.xuguobin.club/api/elm/" //這是我伺服器的api介面
let localURL = 'http://localhost/api/elm/';     //這是本地koa2的api介面

axios.defaults.baseURL = httpURL;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

export default class AxiosCache {
	constructor() {
		this.__config = {}
		this.__setting = setting;
		this.init();
	}

	init() {
		this.doFlushSetting(CACHE_KEY, )
	}

	doFlushSetting(key, conf) {
		if (!key && typeof key !== 'string') {
			return
		}
		this.__config[key] = conf
	}
	
	/*判斷狀態碼*/
	resultJudge(code) {
		return code
	}
	
	/*傳送請求資料*/
	sendRequest(key, options) {
		let send = this.__config[this.settingKey][key];
		let self = this;
		let baseURL = send.url;
		send.method == 'get'
			? options.data && (send.url += options.data)
			: send.data = options.data
		axios(send)
			.then(function (response) {
				send.url = baseURL;
				if (self.resultJudge(response.data.status)) {
					options.success(response.data.data)
				} else {
					options.fail
						? options.fail(response.data.data)
						: self.handleErrorCase(response.data.status)
				}
			}).catch(function (error) {
				self.handleErrorCase(error)
			})
	}
	
	/*處理錯誤資訊*/
	handleErrorCase(error) {
		if (typeof error == 'Number') {
			console.log(error)
		} else {
			alert(error)
		}
	}
}
複製程式碼

而傳送請求的時候,只需要這樣

getUSer: function() {
     this.userCache.getUser({
         success: res => this.user = res
     })
},
複製程式碼

是不是很簡潔。這樣做,又進一步的解耦了axios操作,你可以對比我github上的elm1和elm2兩個版本結構,一定會有所收穫。

前端的架構追求就是儘量 完美複用和解耦

前端第三次重構

2019.4.14 Github地址:elm3.0

可能並沒有優化多少,但是提供一個思路

elm2版本中的axios處理邏輯是:封裝一個AxiosCache的基類,裡面有一些共用的方法,其他axios物件則繼承這個基類,在各自頁面中進行例項化,如果這個頁面需要請求使用者相關介面則例項化一個UserCache,可如果另一個頁面也有用到則再例項化一個UserCache,重複的例項化讓我覺得效能上的浪費。所以我想到了另外一種不使用類繼承和例項化的axios的結構

elm3版本結構如下

├── axios           // axios操作
|         ├──index.js   // axios配置表
|         ├──base       // axios公共部分
|         |    ├──index.js     //axios公共方法
|         |    └──setting.js  //狀態碼
|         └── user
|               ├──cache.js     //請求函式
|               └──config.js    //配置資訊
複製程式碼

elm3版本中的axios處理邏輯是這樣的:在axios目錄下的index.js中引入各Cache的配置資訊和狀態碼構成一個配置表

// 引入狀態碼錶
import setting from './base/setting'
// 引入config配置表
import userConfig from './user/config';
import goodConfig from './good/config';
import sellerConfig from './seller/config';

export default {
    __setting: setting,
    __config:  {
        'user_cache_key': userConfig,
        'good_cache_key': goodConfig,
        'seller_cache_key': sellerConfig
    }
}

複製程式碼

將這個配置表匯入賦值給Vue(main.js):

import axios from '@/axios' 
Vue.$axios = axios;
複製程式碼

base目錄下的index.js中只保留公共方法 (這裡我使用了Promise)

import axios from 'axios'
import Vue from 'vue'

let httpURL = "http://www.xuguobin.club/api/elm/" //這是我伺服器的api介面
let localURL = 'http://localhost/api/elm/';     //這是本地koa2的api介面

axios.defaults.baseURL = httpURL;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

// 判斷狀態碼
function resultJudge(code) {
	return code
}
// 處理錯誤公共方法
function handleErrorCase(error) {
	if (typeof error == 'Number') {
		console.log(error)
	} else {
		alert(error)
	}
}
// 傳送請求
export default function sendRequest(settingKey, key, data) {
	let send = Vue.$axios.__config[settingKey][key];
	let baseURL = send.url;
	send.method == 'get'
		? data && (send.url += data)
		: send.data = data;
	return new Promise((resolve,reject) => {
		axios(send)
		.then((res)=>{
			send.url = baseURL;
			resultJudge(res.data.status) ? resolve(res.data.data) : reject(res.data.data);
		}).catch((err)=>{
			handleErrorCase(err)
		});
	});
}
複製程式碼

而在其他的Cache頁面的請求函式

import sendRequest from '../base';
const CACHE_KEY = 'good_cache_key'

export default {
	getGood(options) {
		return sendRequest(CACHE_KEY, 'good-getGood',options);
	},
	getGoods(options) {
		return sendRequest(CACHE_KEY, 'good-getGoods',options);
	}
}
複製程式碼

這樣做的好處是在頁面第一次載入時就制定好了一張ajax請求的資訊表並儲存在Vue.$axios中,後期頁面使用時不需求例項化,直接按表索引就好了

前端第四次重構?

未完待續...... 你有好的架構也歡迎你fork我的master版本! ^_^

相關文章