Оптимизация архитектуры проекта Vue

Vue.js

написать впереди

В этом блоге я представлю архитектурную идею Vue. Конечно, это просто архитектура Vue, которую я обобщил на основе проектов, с которыми я столкнулся. Это небольшие три раунда, которые я нашел. Если у вас хорошая архитектура , вы можете посоветовать.

Хорошо, давайте начнем говорить!

Введение в рефакторинг

  1. Первый рефакторинг:Централизованные запросы ajax
  2. Второй рефакторинг:Использование архитектуры наследования классов
  3. Третий рефакторинг:Использовать схему таблицы конфигурации
  4. Четвертый рефакторинг:Используйте наследование классов + одноэлементную архитектуру

2019.9.16 Последний измененный адрес 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 Адрес на гитхабе: elm1.0

Структура каталогов

├── src                // 生产目录
│   ├── api            // axios操作
│   ├── components     // 组件 
│   ├── router         // 路由
│   ├── store          // vuex状态管理器
│	├── App.vue        // 首页
│   └── main.js        // Webpack 预编译入口

Все верно, просто ajax запросы концентрируются в каталоге apiФайл index.js в каталоге API

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 Адрес на гитхабе: 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 от страницы, код состояния необходимо проверять и обрабатывать сообщения об ошибках после каждого запроса.

На самом деле вообще не обязательно заходить на каждую страницу, эти публичные операции можно разместить вместе в базовом классе аксиом

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 дополнительно развязана.Вы можете сравнить две структуры версий elm1 и elm2 на моем github, и вы обязательно что-то выиграете.

Архитектурное стремление внешнего интерфейса состоит в том, чтобы попытаться усовершенствовать повторное использование и развязку.

Третий рефакторинг фронтенда

2019.4.14 Адрес на гитхабе: elm3.0

Возможно, это не сильно оптимизировано, но дает представление

Логика обработки axios в версии elm2 следующая: инкапсулировать базовый класс AxiosCache, который имеет некоторые общие методы. Другие объекты axios наследуют этот базовый класс и создают их экземпляры на своих соответствующих страницах. Если страница должна запрашивать пользовательские интерфейсы, instance Создайте экземпляр UserCache, но если другая страница также полезна, создайте экземпляр другого UserCache.Повторное создание экземпляра заставляет меня чувствовать, что это пустая трата производительности. Поэтому я подумал о другой структуре аксиом, которая не использует наследование и создание экземпляров классов.

Структура версии elm3 выглядит следующим образом.

├── axios           // axios操作
|         ├──index.js   // axios配置表
|         ├──base       // axios公共部分
|         |    ├──index.js     //axios公共方法
|         |    └──setting.js  //状态码
|         └── user
|               ├──cache.js     //请求函数
|               └──config.js    //配置信息

Логика обработки axios в версии elm3 выглядит следующим образом:axiosв каталогеindex.jsИнформация о конфигурации и код состояния каждого кэша вводятся в таблицу конфигурации.

// 引入状态码表
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)
		});
	});
}

И в функции запроса других страниц кэша

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В середине более поздние страницы не нужно создавать, когда они используются, просто нажмите непосредственно на индекс таблицы.

Четвертый рефакторинг фронтенда

2019.9.16 Адрес на гитхабе: elm3.1

Проблема, связанная с использованием архитектуры наследования в версии elm2.0, обсуждалась ранее: повторная реализация приводит к потере производительности. Поэтому используйте другую структуру таблицы конфигурации axios, которая не использует наследование и инстанцирование классов, то есть версию elm3.0. На самом деле проблема может быть полностью решена синглтоном, я поленился и не додумался до этого.

Возьмите GoodCache в качестве примера

import BaseCache from '../base/base';
import config from './config';
const CACHE_KEY = 'good_cache_key';

class GoodCache extends BaseCache {
  constructor() {
    super();
    this.settingKey = CACHE_KEY;
  }

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

  getGood(options) {
    this.sendRequest('good-getGood', options);
  }

  getGoods(options) {
    this.sendRequest('good-getGoods', options);
  }
}

export default (function() {
  let goodCache;
  return function() {
    if (!goodCache) {
      goodCache = new GoodCache();
    }
    return goodCache;
  };
})();

Внедрить и использовать на других страницах:

import GoodCache from '@/axios/good/cache';

created: function() {
    this.goodCache = GoodCache();
    this.getGood();
}

Независимо от того, сколько страниц вызывают API в GoodCache, экземпляр GoodCache будет создан только один раз, и в глобальном масштабе существует только один объект goodCache.

Пятый рефакторинг фронтенда?

Продолжение следует... У вас хорошая архитектура, и вы можете разветвить мою мастер-версию! ^_^