Текущая ситуация
Я реализовал плагин Vue, который управляет вызовами к серверу с помощью очередей.
У меня есть пользовательский интерфейс автосохранения, который всякий раз, когда пользователь оставляет вход, Код на стороне клиента отправляет UiState на сервер для хранения в БД. Так как пользователь может вводить и оставлять много входов за короткое время, Ajax Запросы могут не поступать с сервера последовательно.
Поскольку я отправляю полный объект UiState, и сервер может не получать запросы в том же При заказе как отправить, я могу сохранить не последнее изменение на сервере, а предыдущее.
Вот почему я реализовал следующий плагин для Vue. Он использует Очередь и, если к тому времени, когда сервер отвечает на запрос на сохранение, был запущен новый запрос на сохранение, он отправляет только последний запрос на сохранение.
import axios from "Axios"
import qs from 'qs';
export default {
install(Vue, pluginOptions) {
var ajs = {}; //ajax-saving
var defaultPluginOptions = {
indicatorElement: null
};
// saving flags
ajs.isSaving = false;
ajs.pendingSaving = false;
ajs.pendingRequests = [];
// the indicator element
ajs.indicator = null;
ajs.indicatorTitle = null;
Vue.prototype.$ajaxSaveData = function (serverUrl, data, callback) {
//use pending flag for the function to recall itself when it finishes
if (ajs.isSaving) {
ajs.pendingSaving = true;
ajs.pendingRequests.push({ serverUrl: serverUrl, data: data, callback: callback });
console.log('%cAjaxSaving %cThe save action is queued!', 'color:#67A9BF;', 'color:#E3DC29');
return;
}
onSaveStarted();
axios({
url: serverUrl,
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
})
.then(result => {
onSaveEnded();
if (callback) callback(true, result);
})
.catch(function (error) {
console.log(error);
onSaveEnded(true);
if (callback) callback(false);
})
}
// saving events
var onSaveStarted = function () {
ajs.isSaving = true;
ajs.indicator.removeClass('error');
ajs.indicator.addClass('saving');
ajs.indicator.show();
ajs.indicatorTitle.html("Saving");
console.log('%cAjaxSaving %cStarted!', 'color:#67A9BF;', 'color:#7DBF67');
}
var onSaveEnded = function (error) {
ajs.isSaving = false;
ajs.indicator.removeClass('saving');
if (error) {
ajs.indicator.addClass('error');
ajs.indicatorTitle.html("Error");
console.log('%cAjaxSaving %cError!', 'color:#67A9BF;', 'color:#E60909');
} else {
ajs.indicatorTitle.html("Saved");
}
console.log('%cAjaxSaving %cEnded!', 'color:#67A9BF;', 'color:#091152');
// execute the pending savings
if (ajs.pendingSaving) {
var pendingToProcess = ajs.pendingRequests;
ajs.pendingRequests = [];
ajs.pendingSaving = false;
console.log('%cAjaxSaving %cExecuting Pending!', 'color:#67A9BF;', 'color:#E83CC5');
// process all pending request found in stack.
// skip older requests if newer are found
var req;
var processedRequests = [];
while ((req = pendingToProcess.pop()) != null) {
if (!processedRequests.includes(req.serverUrl)) {
processedRequests.push(req.serverUrl);
var executingReq = req;
setTimeout(function () {
Vue.prototype.$ajaxSaveData(executingReq.serverUrl, executingReq.data, executingReq.callback);
}, 0);
}
}
}
}
var testOptions = function () {
if (!ajs.options.indicatorElement) {
throw ('indicator element is not set');
}
}
//TODO: Remove jquery
// Plugin initialization
var createIndicator = function () {
ajs.indicator = $(ajs.options.indicatorElement);
ajs.indicatorTitle = ajs.indicator.find('span');
if (ajs.indicatorTitle.length === 0) {
ajs.indicatorTitle = $('<span></span>');
ajs.indicator.append(ajs.indicatorTitle);
}
}
var initialize = function () {
//initialize options and elements needed from plugin
ajs.options = $.extend({}, defaultPluginOptions, pluginOptions);
testOptions();
createIndicator();
};
initialize();
}
}
Чтобы использовать это:
import Vue from "vue";
import VueAjaxSaving from '@/Plugins/VueAjaxSaving'
Vue.use(VueAjaxSaving, { indicatorElement: '#ajaxIndicator' });
new Vue({
data: {
uiState: {....}
},
methods:{
updateUiState() {
this.$ajaxSaveData('/Page/UpdateUiState', { uiState: this.uiState }, () => this.someCallback());
},
}
})
Плагин принимает в качестве параметра элемент (селектор jQuery) и обновляет пользовательский интерфейс с состоянием сохранения.
Необходимость
Я рефакторинг своего кода для использования Vuex для моего состояния, и я хочу, чтобы модуль Vuex обрабатывал сохранение, когда что-то мутировало.
Я хочу предоставить своим модулям Vuex функцию, которая обрабатывает сохранение так же, как мои компоненты Vue. С легкостью вызова ajaxSaveData('url',data).then(...)
из любого действия Vuex.
Мне нужно обновить часть пользовательского интерфейса со статусом сохранения.
Вопросы
Что мне нужно использовать для удовлетворения моих потребностей?
- Плагин Vuex?
- Функция класса, которая импортируется в файл модуля и используется как грязная, как звучит?
- Новый модуль, который содержит все логики сохранения c ajaxSaveData? Я полагаю, что любой модуль может отправлять свои действия.
Как обновить пользовательский интерфейс для ajaxSaveData Vuex (плагин / класс / модуль)?