programing

AngularJS: 컨트롤러를 완전히 새로고침하지 않고 해시 및 라우팅 변경

newsource 2023. 3. 21. 22:13

AngularJS: 컨트롤러를 완전히 새로고침하지 않고 해시 및 라우팅 변경

다음과 같은 루트를 가진 컨트롤러가 있습니다.

#/1234/1234

컨트롤러를 완전히 새로고침하지 않고 경로를 변경하여 컨트롤러 내의 다른 항목의 위치를 일정하게 유지할 수 있도록 합니다(스크롤 목록).

몇 가지 방법을 생각해 낼 수 있지만, 모두 꽤 못생겼어요.이런 걸 할 수 있는 좋은 방법이 있을까요?reload On Search: false를 시험해 봤는데 아무것도 바뀌지 않는 것 같습니다.

똑같은 도전을 했는데

다른 Stack Overflow 응답에서 문제가 발생한 해킹을 발견했습니다.

꽤 깨끗한 솔루션 - $location을 설정하는 컨트롤러에 이러한 행을 추가한 것뿐입니다.경로:

var lastRoute = $route.current;
$scope.$on('$locationChangeSuccess', function(event) {
    $route.current = lastRoute;
});

물론 컨트롤러에 $route를 주입했습니다.

그러나 여전히 Angular에서는 "DoNotFollowRoutesOnPathChange" 기능이 누락된 것 같습니다.JS.

/젠스

업데이트: 이 이벤트를 들으면 $routeProvider Configuration의 추가 사용이 효과적으로 중지되므로 이 캐치를 현재 경로로만 제한해야 했습니다.

    var lastRoute = $route.current;
    if ($route.current.$route.templateUrl.indexOf('mycurrentpath') > 0) {
        $route.current = lastRoute;         
    }

점점 못생겨지고...

간단한 답변:

를 사용할 수 있습니다.$location.search()방법을 알려주세요.이 노래를 들으면서"$routeUpdate"다른 루트 이벤트 대신 범위 내의 이벤트.$route API.

설명:

  1. 먼저 (이미 알고 있는) 추가reloadOnSearch: false고객님께$routeProvider:

    $routeProvider.when('/somewhere', {
        controller: 'SomeCtrl',
        reloadOnSearch: false
    })
    
  2. 앵커 태그 변경href또는ng-href로.href="#/somewhere?param=value"이것은 트리거할 것이다.$routeChangeSuccesspath part(경로 부분일 경우)/somewhere)는 현재 위치와 다릅니다.그렇지 않으면 트리거됩니다.$routeUpdate이벤트입니다.

  3. 범위에서 이벤트 듣기:

    $scope.$on("$routeUpdate", function(event, route) {
        // some code here
    });
    
  4. 코드의 검색 매개 변수를 변경하려면$location.search()방법.$location.API를 검색합니다.

reloadOnSearch를 false로 설정하면?a=b&c=d새로고침되지 않은 URL의 일부입니다.그러나 새로고침이 없으면 실제 위치를 예쁘게 변경할 수 없습니다.

편집

ngRoute를 사용하는 경우 더 나은 접근법:

/**
 * Add skipReload() to $location service.
 *
 * See https://github.com/angular/angular.js/issues/1699
 */
app.factory('location',
  ['$rootScope', '$route', '$location',
  function($rootScope, $route, $location) {

  $location.skipReload = function() {
    var lastRoute = $route.current;

    var deregister = $rootScope.$on('$locationChangeSuccess',
                                    function(e, absUrl, oldUrl) {
      console.log('location.skipReload', 'absUrl:', absUrl, 'oldUrl:', oldUrl);
      $route.current = lastRoute;
      deregister();
    });

    return $location;
  };

  return $location;
}]);

사용방법:

app.controller('MyCtrl', ['$scope', 'location', function($scope, location) {
  $scope.submit = function() {
    location.skipReload().path(path);
  };
}]);

구답

Jens X Augustsson의 답변을 바탕으로 재사용 가능한 공장을 작성했습니다.

app.factory('DoNotReloadCurrentTemplate', ['$route', function($route) {
  return function(scope) {
    var lastRoute = $route.current;
    scope.$on('$locationChangeSuccess', function() {
      if (lastRoute.$$route.templateUrl === $route.current.$$route.templateUrl) {
        console.log('DoNotReloadCurrentTemplate',
                    $route.current.$$route.templateUrl);
        $route.current = lastRoute;
      }
    });
  };
}]);

AngularJS 1.0.6과 연동

사용방법:

app.controller('MyCtrl',
  ['$scope', 'DoNotReloadCurrentTemplate',
  function($scope, DoNotReloadCurrentTemplate) {

  DoNotReloadCurrentTemplate($scope);
}]);

AngularJS의 문제: https://github.com/angular/angular.js/issues/1699

HTML5의 창을 처리하는 팩토리를 정의합니다.이와 같은 이력(안드로이드에서도 동작하도록 하기 위해 Stack을 소유하고 있습니다.

.factory('History', function($rootScope) {
    var StateQueue = [];
    var StatePointer = 0;
    var State = undefined;
    window.onpopstate = function(){
        // called when back button is pressed
        State = StateQueue.pop();
        State = (State)?State:{};
        StatePointer = (StatePointer)?StatePointer-1:0;
        $rootScope.$broadcast('historyStateChanged', State);
        window.onpopstate = window.onpopstate;

    }
    return {
        replaceState : function(data, title, url) {
            // replace current state
            var State = this.state();
            State = {state : data};
            window.history.replaceState(State,title,url);
            StateQueue[StatePointer] = State;
            $rootScope.$broadcast('historyStateChanged', this.state());
        },
        pushState : function(data, title, url){
            // push state and increase pointer
            var State = this.state();
            State = {state : data};
            window.history.pushState(State,title,url);
            StateQueue.push(State);
            $rootScope.$broadcast('historyStateChanged', this.state());
            StatePointer ++;
        },
        fakePush : function(data, title, url) {
            // call this when you do location.url(url)
            StateQueue.push((StateQueue.length - 1 >= 0)?StateQueue[StateQueue.length -1]:{});
            StatePointer ++;
            $rootScope.$broadcast('historyStateChanged', this.state());
        },
        state : function() {
            // get current state
            return (StateQueue[StatePointer])?StateQueue[StatePointer]:{};
        },
        popState : function(data) {
            // TODO manually popState
        },
        back : function(data) {
            // TODO needed for iphone support since iphone doesnt have a back button
        }
    }
})

의존 스코프에 청취자를 몇 명 추가하면 다음과 같이 문제가 없습니다.

$scope.$on('historyStateChanged', function(e,v) {
        if(v)
            $scope.state = v;
        else
            $scope.state = {}
    });

그게 내가 하는 방식이야제 관점에서는 URL은 새로운 뷰가 로드될 때만 변경됩니다.어쨌든 앵글 팀이 의도한 건 그런 것 같아요.모델의 앞으로/뒤로 버튼을 매핑하려면 HTML5 창에서 매핑해 보십시오.역사

내가 도울 수 있으면 좋겠다.건배, 하인리히

용도:

$routeProvider.when('/somewhere', {
    controller: 'SomeCtrl',
    reloadOnSearch: false
})

이로 인해 쿼리 파라미터 변경 시뿐만 아니라 해시 변경 시 컨트롤러가 새로고침되지 않습니다.

2015년에 이곳에 상륙한 경우:여기서의 진짜 답은 이러한 해킹을 사용하지 않고(위의 방법을 사용하면 해결 방법 등을 사용할 수 없게 되기 때문에 굳이 이름을 붙일 수 있습니다) ui-router로 전환하는 것입니다.

여기 차이점에 대한 편리한 프레젠테이션이 있습니다.구현은 $route를 $state로 교환하고 상태를 이름으로 변환하는 것만으로 간단해야 합니다.

현재 루트를 href로 참조하고 새로고침하지 않고 상태를 변경하는 옵션 get 파라미터를 사용하는 방식으로 전환하고 있습니다.자세한 내용은 여기를 참조하십시오.

이 간단한 솔루션(놀랍게도)은 나에게 효과적이다.

$state.params.id = id;  //updating the $state.params somehow prevents reloading the state
$location.path('/articles/' + id);

단, Back and Forward 버튼 상태 새로고침은 방지되지 않습니다.주의: angularjs 1.2.7과 ui-router 0.0.1을 사용하고 있습니다(오래되었다는 것을 알고 있습니다).

플러그인은 다음과 같습니다.

사용방법:

$location.update_path('/notes/1');

이 은, 「 」를 사용하지 않고 할 수 .$locationChange~ ★★★★★★★★★★★★★★★★★」HistoryState ha ha ha ha ha ha ha ha ha ha haroute의 약속 옵션

article 이 조작을 실시할 수 , 예를 들어, 이 조작을 할 수 있는 루트, 또는 이 조작을 실시합니다.

$routeProvider.when(
    '/article/:number',
    {
        templateUrl : 'partial.html',
        controller : 'ArticleCtrl',
        resolve : {
            load : ['$q', '$routeParams', function($q, $routeParams) {
                var defer = $q.defer();

                //number was specified in the previous route parameters, means we were already on the article page
                if ($routeParams.number)
                    //so dont reload the view
                    defer.reject('');
                //otherwise, the number argument was missing, we came to this location from another route, load the view
                else
                    defer.resolve();

                return defer.promise;
            }]
        }
    }
);

언급URL : https://stackoverflow.com/questions/12115259/angularjs-change-hash-and-route-without-completely-reloading-controller