У нас была аналогичная проблема, которую нужно было решить в нашем одностраничном веб-приложении на моей работе. У нас были некоторые страницы, которые могли быть грязными, и если бы это было так, мы хотели предотвратить переход с этой страницы до тех пор, пока пользователь не подтвердит, что это нормально. Поскольку мы хотели предотвратить навигацию, мы не могли прослушивать событие onhashchange, которое запускается после изменения хеша, а не до этого. Поэтому мы решили переопределить LocationProxy по умолчанию, включив в него логику, которая позволяла нам дополнительно предотвращать навигацию до изменения местоположения.
Имея это в виду, вот прокси, который мы использовали:
PreventableLocationProxy = (function () {
function PreventableLocationProxy(delegateProxy, navigationValidators) {
/// <summary>This is an implementation of a Sammy Location Proxy that allows cancelling of setting a location based on the validators passed in.</summary>
/// <param name="delegateProxy" type="Sammy.DefaultLocationProxy">The Location Proxy which we will delegate all method calls to.</param>
/// <param name="navigationValidators" type="Function" parameterArray="true" mayBeNull="true">One or more validator functions that will be called whenever someone tries to change the location.</param>
this.delegateProxy = delegateProxy;
this.navigationValidators = Array.prototype.slice.call(arguments, 1);
}
PreventableLocationProxy.prototype.bind = function () {
this.delegateProxy.bind();
};
PreventableLocationProxy.prototype.unbind = function () {
this.delegateProxy.unbind();
};
PreventableLocationProxy.prototype.getLocation = function () {
return this.delegateProxy.getLocation();
};
PreventableLocationProxy.prototype.setLocation = function (new_location) {
var doNavigation = true;
_.each(this.navigationValidators, function (navValidator) {
if (_.isFunction(navValidator)) {
// I don't just want to plug the result of the validator in, it could be anything!
var okayToNavigate = navValidator(new_location);
// A validator explicitly returning false should cancel the setLocation call. All other values will
// allow navigation still.
if (okayToNavigate === false) {
doNavigation = false;
}
}
});
if (doNavigation) {
return this.delegateProxy.setLocation(new_location);
}
};
return PreventableLocationProxy;
}());
Этот код довольно прост сам по себе, это объект javascript, который принимает прокси делегата, а также одну или несколько функций проверки. Если какой-либо из этих валидаторов явно возвращает false, навигация невозможна, и местоположение не изменится. В противном случае навигация разрешена. Чтобы это работало, нам пришлось переопределить стандартную обработку кликов наших тегов привязки, чтобы направить ее через Sammy.Application.setLocation. Однако после того, как это было сделано, это позволило нашему приложению обрабатывать логику грязной страницы.
На всякий случай вот наш валидатор грязной страницы:
function preventNavigationIfDirty(new_location) {
/// <summary>This is an implementation of a Sammy Location Proxy that allows cancelling of setting a location based on the validators passed in.</summary>
/// <param name="new_location" type="String">The location that will be navigated to.</param>
var currentPageModels = [];
var dirtyPageModels = [];
//-----
// Get the IDs of the current virtual page(s), if any exist.
currentPageModels = _.keys(our.namespace.currentPageModels);
// Iterate through all models on the current page, looking for any that are dirty and haven't had their changes abored.
_.forEach(currentPageModels, function (currentPage) {
if (currentPage.isDirty() && currentPage.cancelled === false) {
dirtyPageModels.push(currentPage);
}
});
// I only want to show a confirmation dialog if we actually have dirty pages that haven't been cancelled.
if (dirtyPageModels.length > 0) {
// Show a dialog with the buttons okay and cancel, and listen for the okay button's onclick event.
our.namespace.confirmDirtyNavigation(true, function () {
// If the user has said they want to navigate away, then mark all dirty pages with the cancelled
// property then do the navigating again. No pages will then prevent the navigation, unlike this
// first run.
_.each(dirtyPageModels, function (dirtyPage) {
dirtyPage.cancelled = true;
});
our.namespace.sammy.setLocation(new_location);
});
// Returns false in order to explicitly cancel the navigation. We don't need to return anything in any
// other case.
return false;
}
}
Помните, что это решение не будет работать, если пользователь явно изменит местоположение, но это не тот вариант использования, который мы хотели поддерживать. Надеюсь, это приблизит вас к собственному решению.
person
Smartboy
schedule
30.05.2014