programing

뒤로 버튼을 Angular와 함께 사용하려면 어떻게 해야 합니까?JS UI 라우터 상태 시스템?

showcode 2023. 3. 26. 11:55
반응형

뒤로 버튼을 Angular와 함께 사용하려면 어떻게 해야 합니까?JS UI 라우터 상태 시스템?

ui-router를 사용하여 angularjs 한 페이지 어플리케이션을 구현하였습니다.

원래 개별 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-router 스테이트 머신을 유지하면서 Back 버튼 기능을 활성화하려면 어떻게 해야 합니까?

메모

, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다, 하다.$window.history.back()모두 질문의 중요한 부분을 놓쳤다.기록이 점프할 때 응용 프로그램 상태를 올바른 상태 위치로 복원하는 방법(뒤로/앞으로/새로 고침).그것을 염두에 두고, 계속 읽어 주세요.


의 백(이력)는, 순수 「」, 「/」(이력)의 에 실시할 수 .ui-router단, doing.state-machine이 합니다.

몇 가지 컴포넌트가 필요합니다.

  • 일의의 URL브라우저는 URL을 변경할 때만 Back/Forward 버튼을 활성화하기 때문에 방문한 상태별로 원하는 URL을 생성해야 합니다.단, 이러한 URL에는 상태 정보가 포함되어 있을 필요는 없습니다.

  • 세션 서비스생성된 각 URL은 특정 상태와 관련이 있으므로 url-state 쌍을 저장하여 각도 앱이 뒤로/앞으로 또는 새로 고침 클릭으로 재시작된 후 상태 정보를 검색할 수 있는 방법이 필요합니다.

  • 상태 이력ui-router 상태 사전은 고유한 URL로 키 지정됩니다.HTML5에 의존할 수 있다면 HTML5 History API를 사용할 수 있지만, 저처럼 사용할 수 없다면 몇 줄의 코드로 직접 구현할 수 있습니다(아래 참조).

  • 로케이션 서비스마지막으로 코드에 의해 내부적으로 트리거되는 UI 라우터 상태 변경과 사용자가 브라우저 버튼을 클릭하거나 브라우저 바에 내용을 입력하는 데 의해 트리거되는 일반적인 브라우저 URL 변경을 모두 관리할 수 있어야 합니다.무엇이 원인이 되었는지 혼동하기 쉽기 때문에 이 모든 것이 다소 까다로울 수 있습니다.

여기 각 요건의 실장이 있습니다.모든 것을 3개의 서비스로 정리했습니다.

세션 서비스

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용 래퍼입니다.sessionStorage물건.나는 여기서 명확히 하기 위해 그것을 줄였다.상세한 것에 대하여는, 다음을 참조해 주세요.Angular를 사용하여 페이지 새로 고침을 처리하는 방법JS 단일 페이지 응용 프로그램

스테이트 히스토리 서비스

class StateHistoryService
    @$inject:['sessionService']
    constructor:(@sessionService) ->

    set:(key, state)->
        history = @sessionService.stateHistory() ? {}
        history[key] = state
        @sessionService.stateHistory history

    get:(key)->
        @sessionService.stateHistory()?[key]

angular
.module 'app.Services'
.service 'stateHistoryService', StateHistoryService

StateHistoryService는 생성된 고유 URL에 의해 키 입력된 이력 상태의 저장 및 취득을 관리합니다.이것은 사실 사전 형식의 오브젝트를 위한 편리한 포장지일 뿐입니다.

주 로케이션 서비스

class StateLocationService
    preventCall:[]
    @$inject:['$location','$state', 'stateHistoryService']
    constructor:(@location, @state, @stateHistoryService) ->

    locationChange: ->
        return if @preventCall.pop('locationChange')?
        entry = @stateHistoryService.get @location.url()
        return unless entry?
        @preventCall.push 'stateChange'
        @state.go entry.name, entry.params, {location:false}

    stateChange: ->
        return if @preventCall.pop('stateChange')?
        entry = {name: @state.current.name, params: @state.params}
        #generate your site specific, unique url here
        url = "/#{@state.params.subscriptionUrl}/#{Math.guid().substr(0,8)}"
        @stateHistoryService.set url, entry
        @preventCall.push 'locationChange'
        @location.url url

angular
.module 'app.Services'
.service 'stateLocationService', StateLocationService

StateLocationService는 두 이벤트를 합니다.

  • location Change.이것은 브라우저 위치가 변경되었을 때(일반적으로 뒤로/앞으로/새로 고침 버튼을 눌렀을 때 또는 앱이 처음 시작되었을 때 또는 사용자가 URL에 입력할 때)라고 불립니다.현재 location.url의 상태가 에 존재하는 경우StateHistoryServiceUI를 통해 할 때 합니다.$state.go.

  • 상태 변경이것은 내부에서 상태를 이동할 때 호출됩니다.현재 상태의 이름과 파라미터는StateHistoryService에에 URL 。이 생성된 URL은 사용자가 원하는 모든 것이 될 수 있으며, 사람이 읽을 수 있는 방법으로 상태를 식별할 수도 있고 식별할 수도 없습니다.이 경우 상태 매개 변수와 GUID에서 파생된 무작위로 생성된 숫자 시퀀스를 사용하고 있습니다(GUID 생성기 스니펫은 발 참조).으로 "URL" 또는 "URL"을 사용하여 됩니다.@location.url url브라우저 이력 스택에 URL을 추가하여 앞으로/뒤로 버튼을 활성화합니다.

의 큰 는, 「」를 입니다.@location.url url stateChange는 메서드를 .$locationChangeSuccess, 즉 "이벤트", "이벤트", "", "이벤트"locationChange방법.방법. Equally calling the 동등하게 호출하는 것은@state.go부에서locationChange will trigger the 를 트리거합니다.$stateChangeSuccess event and so the 이벤트 등stateChange방법.법 이건 매우 혼란스럽고, 브라우저 역사를 엉망진화할 수 없습니다.이것은 매우 혼란스럽고 브라우저의 역사를 끝없이 혼란스럽게 합니다.

이치노 보면 '아까보다'가 나와요.preventCall 어레이어레이」)pop ★★★★★★★★★★★★★★★★★」push마다 다른 메서드로 되지 않도록 어떤 메서드가 호출될 때마다 다른 메서드는 1회성 메서드만 호출되지 않습니다.이 기술은 $ 이벤트의 올바른 트리거링을 방해하지 않고 모든 것을 올바르게 유지합니다.

우리가 할 이다.HistoryService상태 전환 라이프사이클에서 적절한 시점에 방법을 제시합니다.은 Angular에서 . 앱 JS ».run을 사용하다

Angular app.

angular
.module 'app', ['ui.router']
.run ($rootScope, stateLocationService) ->

    $rootScope.$on '$stateChangeSuccess', (event, toState, toParams) ->
        stateLocationService.stateChange()

    $rootScope.$on '$locationChangeSuccess', ->
        stateLocationService.locationChange()

GUID 생성

Math.guid = ->
    s4 = -> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1)
    "#{s4()}#{s4()}-#{s4()}-#{s4()}-#{s4()}-#{s4()}#{s4()}#{s4()}"

이 모든 기능을 갖추면 앞으로/뒤로 버튼과 새로 고침 버튼이 모두 예상대로 작동합니다.

app.run(['$window', '$rootScope', 
function ($window ,  $rootScope) {
  $rootScope.goBack = function(){
    $window.history.back();
  }
}]);

<a href="#" ng-click="goBack()">Back</a>

여러 가지 제안을 테스트해 본 결과, 가장 쉬운 방법이 가장 좋은 경우가 많다는 것을 알게 되었습니다.

angular ui-router를 사용하여 최적의 상태로 돌아가기 위한 버튼이 필요한 경우:

<button onclick="history.back()">Back</button>

또는

<a onclick="history.back()>Back</a>

// 경고는 href를 설정하지 않습니다.그렇지 않으면 경로가 파손됩니다.

설명:표준 관리 애플리케이션을 가정합니다.개체 검색 -> 개체 보기 -> 개체 편집

상태에서 각도 용액 사용:

검색 -> 보기 -> 편집

수신인:

검색 -> 표시

브라우저의 [뒤로]버튼을 클릭하면 다시 표시됩니다.

검색 -> 보기 -> 편집

그리고 그것은 논리적이지 않다.

그러나 간단한 솔루션 사용

<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 및 $140 브 the젝트 。ui-router's $state object활성 이력 엔트리가 변경될 때마다 팝스테이트이벤트가 창으로 디스패치 됩니다
$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}
            );
        }
    };
}

그 후, 뒤로/앞으로 버튼은 부드럽게 동작합니다.

주의: window.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;
                });
        }]);

언급URL : https://stackoverflow.com/questions/22247294/how-do-i-get-the-back-button-to-work-with-an-angularjs-ui-router-state-machine

반응형