Как мне получить кнопку Назад, чтобы работать с пользовательским интерфейсом маршрутизаторов в AngularJS государственной машины?
я реализовал приложение angularjs одной страницы с помощью ui-router.
Первоначально я идентифицировал каждое состояние с помощью отдельного url-адреса, однако это сделало для недружественных, GUID упакованных URL-адресов.
Так что теперь я определил свой сайт как гораздо более простую государственную машину. Состояния не идентифицируются URL-адресами, а просто переходят по мере необходимости, например:
Определение Вложенных Государства
angular
.module 'app', ['ui.router']
.config ($stateProvider) ->
$stateProvider
.state 'main',
templateUrl: 'main.html'
controller: 'mainCtrl'
params: ['locationId']
.state 'folder',
templateUrl: 'folder.html'
parent: 'main'
controller: 'folderCtrl'
resolve:
folder:(apiService) -> apiService.get '#base/folder/#locationId'
переход в определенное состояние
#The ui-sref attrib transitions to the 'folder' state
a(ui-sref="folder({locationId:'{{folder.Id}}'})")
| {{ folder.Name }}
эта система работает очень хорошо, и я люблю ее чистый синтаксис. Однако, поскольку я не использую URL-адреса, кнопка "назад" не работает.
Как сохранить мой аккуратный ui-маршрутизатор state-machine, но включить функцию кнопки "Назад"?
8 ответов:
Примечание
ответы, которые предлагают использовать вариации
$window.history.back()все пропустили важную часть вопроса: как восстановить состояние приложения к правильному положению-положению по мере того как история скачет (назад/вперед/освежает). Имея это в виду, пожалуйста, читайте дальше.
да, можно иметь браузер назад / вперед (история) и обновить во время работы чистого
ui-routerstate-machine, но это занимает немного времени.вам нужно несколько компонентов:
Уникальные URL-Адреса. Браузер включает кнопки Назад / Вперед только при изменении URL-адресов, поэтому необходимо создать уникальный url-адрес для каждого посещенного состояния. Однако эти URL-адреса не должны содержать никакой информации о состоянии.
Сессия. Каждый сгенерированный url-адрес соотносится с определенным состоянием, поэтому вам нужен способ хранения пар url-состояния, чтобы вы могли извлеките информацию о состоянии после того, как ваше приложение angular было перезапущено щелчками назад / вперед или обновить.
История Государства. Простой словарь пользовательский интерфейс-маршрутизатор государства ввел уникальный URL-адрес. Если вы можете положиться на HTML5, то вы можете использовать HTML5 History API, но если, как и я, вы не можете, то вы можете реализовать его самостоятельно в нескольких строках кода (см. ниже).
Обслуживания. Наконец, вы должны иметь возможность управлять как изменениями состояния пользовательского интерфейса-маршрутизатора, вызванными внутренним кодом, так и обычными изменениями url-адреса браузера, обычно вызываемыми пользователем, нажимающим кнопки браузера или вводящим материал в панель браузера. Все это может быть немного сложно, потому что легко запутаться в том, что вызвало что.
вот моя реализация каждого из этих требований. Я связал все в три службы:
в Сеанс Обслуживания
class SessionService setStorage:(key, value) -> json = if value is undefined then null else JSON.stringify value sessionStorage.setItem key, json getStorage:(key)-> JSON.parse sessionStorage.getItem key clear: -> @setStorage(key, null) for key of sessionStorage stateHistory:(value=null) -> @accessor 'stateHistory', value # other properties goes here accessor:(name, value)-> return @getStorage name unless value? @setStorage name, value angular .module 'app.Services' .service 'sessionService', SessionServiceэто обертка для javascript
app.run(['$window', '$rootScope', function ($window , $rootScope) { $rootScope.goBack = function(){ $window.history.back(); } }]); <a href="#" ng-click="goBack()">Back</a>
после тестирования различных предложений, я обнаружил, что самый простой способ-лучший.
Если вы используете угловой ui-маршрутизатор и что вам нужна кнопка, чтобы вернуться лучше всего это:
<button onclick="history.back()">Back</button>или
<a onclick="history.back()>Back</a>// Предупреждение Не устанавливайте href или путь будет нарушен.
объяснение: Предположим, стандартное приложение управления. Поиск объекта - > просмотр объекта - > редактировать объект
использование угловых решений Из этого состояние :
Поиск -> Вид -> Редактирование
To:
Поиск -> Вид
Ну это то, что мы хотели, за исключением того, если теперь вы нажмете кнопку браузера назад вы будете там снова:
Поиск -> Вид -> Редактирование
и это не логично
однако с помощью простого решения
<a onclick="history.back()"> Back </a>от :
Поиск -> Вид -> Редактирование
после нажатия на кнопки :
Поиск -> Вид
после нажатия на кнопку браузера назад:
Поиск
последовательность соблюдается. : -)
Если вы ищете самую простую кнопку "назад", то вы можете настроить директиву следующим образом:
.directive('back', function factory($window) { return { restrict : 'E', replace : true, transclude : true, templateUrl: 'wherever your template is located', link: function (scope, element, attrs) { scope.navBack = function() { $window.history.back(); }; } }; });имейте в виду, что это довольно неразумная кнопка "назад", потому что она использует историю браузера. Если вы включите его на своей целевой странице, он отправит пользователя обратно на любой url, с которого он пришел до посадки на ваш.
решение кнопки Назад/Вперед браузера
Я столкнулся с той же проблемой и решал ее с помощьюpopstate eventиз объекта $window иui-router's $state object. Событие popstate отправляется в окно при каждом изменении активной записи журнала.
Элемент$stateChangeSuccessи$locationChangeSuccessсобытия не запускаются при нажатии кнопки браузера, даже если в адресной строке указано новое местоположение.
Итак, предполагая, что вы перешли из состоянияmainдоfolderдоmainопять же, когда вы нажметеbackв браузере, вы должны вернуться кfolderмаршрут. Путь обновляется, но вид не и по-прежнему отображает все, что у вас есть наmain. попробуйте это:angular .module 'app', ['ui.router'] .run($state, $window) { $window.onpopstate = function(event) { var stateName = $state.current.name, pathname = $window.location.pathname.split('/')[1], routeParams = {}; // i.e.- $state.params console.log($state.current.name, pathname); // 'main', 'folder' if ($state.current.name.indexOf(pathname) === -1) { // Optionally set option.notify to false if you don't want // to retrigger another $stateChangeStart event $state.go( $state.current.name, routeParams, {reload:true, notify: false} ); } }; }кнопки Назад/Вперед должны работать плавно после этого.
Примечание: проверьте совместимость браузера для окна.onpopstate (), чтобы быть уверенным
может быть решена с помощью простой директивы "go-back-history", это также закрывает окно в случае отсутствия предыдущей истории.
использование директивы
<a data-go-back-history>Previous State</a>Угловое объявления директивы
.directive('goBackHistory', ['$window', function ($window) { return { restrict: 'A', link: function (scope, elm, attrs) { elm.on('click', function ($event) { $event.stopPropagation(); if ($window.history.length) { $window.history.back(); } else { $window.close(); } }); } }; }])Примечание: работает с помощью ui-маршрутизатора или нет.
кнопка "Назад" тоже не работала для меня, но я понял, что проблема в том, что у меня было
htmlсодержимое внутри моей главной странице, вui-viewэлемент.т. е.
<div ui-view> <h1> Hey Kids! </h1> <!-- More content --> </div>поэтому я переместил содержимое в новый
.htmlфайл, и отметил его как шаблон в.jsфайл с маршрутами.т. е.
.state("parent.mystuff", { url: "/mystuff", controller: 'myStuffCtrl', templateUrl: "myStuff.html" })
history.back()и перейти к Предыдущее состояние часто дают эффект не то, что вы хотите. Например, если у вас есть форма с вкладками, и каждая вкладка имеет собственное состояние, это просто переключило предыдущую выбранную вкладку, а не возврат из формы. В случае вложенных состояний вам обычно нужно так думать о ведьме родительских состояний, которые вы хотите откатить.эта директива решает проблемы
angular.module('app', ['ui-router-back']) <span ui-back='defaultState'> Go back </span>он возвращается в состояние, которое было активным до отображается. Необязательно
defaultState- это имя состояния, которое используется при отсутствии предыдущего состояния в памяти. Также он восстанавливает положение прокруткикод
class UiBackData { fromStateName: string; fromParams: any; fromStateScroll: number; } interface IRootScope1 extends ng.IScope { uiBackData: UiBackData; } class UiBackDirective implements ng.IDirective { uiBackDataSave: UiBackData; constructor(private $state: angular.ui.IStateService, private $rootScope: IRootScope1, private $timeout: ng.ITimeoutService) { } link: ng.IDirectiveLinkFn = (scope, element, attrs) => { this.uiBackDataSave = angular.copy(this.$rootScope.uiBackData); function parseStateRef(ref, current) { var preparsed = ref.match(/^\s*({[^}]*})\s*$/), parsed; if (preparsed) ref = current + '(' + preparsed[1] + ')'; parsed = ref.replace(/\n/g, " ").match(/^([^(]+?)\s*(\((.*)\))?$/); if (!parsed || parsed.length !== 4) throw new Error("Invalid state ref '" + ref + "'"); let paramExpr = parsed[3] || null; let copy = angular.copy(scope.$eval(paramExpr)); return { state: parsed[1], paramExpr: copy }; } element.on('click', (e) => { e.preventDefault(); if (this.uiBackDataSave.fromStateName) this.$state.go(this.uiBackDataSave.fromStateName, this.uiBackDataSave.fromParams) .then(state => { // Override ui-router autoscroll this.$timeout(() => { $(window).scrollTop(this.uiBackDataSave.fromStateScroll); }, 500, false); }); else { var r = parseStateRef((<any>attrs).uiBack, this.$state.current); this.$state.go(r.state, r.paramExpr); } }); }; public static factory(): ng.IDirectiveFactory { const directive = ($state, $rootScope, $timeout) => new UiBackDirective($state, $rootScope, $timeout); directive.$inject = ['$state', '$rootScope', '$timeout']; return directive; } } angular.module('ui-router-back') .directive('uiBack', UiBackDirective.factory()) .run(['$rootScope', ($rootScope: IRootScope1) => { $rootScope.$on('$stateChangeSuccess', (event, toState, toParams, fromState, fromParams) => { if ($rootScope.uiBackData == null) $rootScope.uiBackData = new UiBackData(); $rootScope.uiBackData.fromStateName = fromState.name; $rootScope.uiBackData.fromStateScroll = $(window).scrollTop(); $rootScope.uiBackData.fromParams = fromParams; }); }]);
Comments