$ionicHistory.backView 手动转到上一个状态时状态不正确

我做了一个小实验:http://codepen.io/hawkphil/pen/NqMomm?editors=101

这是我的状态流程(点击按钮):Home ->事实1->事实2->事实 3 ->事实2

Here is my state flow (click on the buttons): Home -> Fact1 -> Fact2 -> Fact3 -> Fact2

在每次状态更改时,我都会在 console.log 中显示 $ionicHistory.backView但是,您可以在 pen.js:64 行中看到,奇怪的事情发生了.$ionicHistory.backView 认为"我从后退按钮到 app.fact2 ,它显示 app.fact1 为前一个状态(行 pen.js:53).这是不正确的,对吧?它应该将 app.fact3 显示为以前的状态,因为我通过单击按钮进入了 app.fact2 状态 MANUALLY.我还显示了来自 $timeout 的值(行 pen.js:59)以防万一它很慢.但还是不对.

On each state change, I am showing in console.log for $ionicHistory.backView However, you can see in pen.js:64 line, weird things happen. The $ionicHistory.backView "thinks" that I got to app.fact2 from a back button, and it shows app.fact1 as the previous state (line pen.js:53). This is incorrect, right? It should show app.fact3 as the previous state because I got to app.fact2 state MANUALLY by clicking the button. I also showed the value from $timeout (line pen.js:59) just in case it's slow. But it's still incorrect.

pen.js:56 stateChangeSuccess
pen.js:64 State change from: tabs.home to: tabs.fact1
pen.js:52 $scope.$watch $ionicHistory.backView change detect. newVal:
pen.js:53 tabs.home
pen.js:58 $timeout after 2 sec $ionicHistory.backView().stateName
pen.js:59 tabs.home
pen.js:56 stateChangeSuccess
pen.js:64 State change from: tabs.fact1 to: tabs.fact2
pen.js:52 $scope.$watch $ionicHistory.backView change detect. newVal:
pen.js:53 tabs.fact1
pen.js:58 $timeout after 2 sec $ionicHistory.backView().stateName
pen.js:59 tabs.fact1
pen.js:56 stateChangeSuccess
pen.js:64 State change from: tabs.fact2 to: tabs.fact3
pen.js:52 $scope.$watch $ionicHistory.backView change detect. newVal:
pen.js:53 tabs.fact2
pen.js:58 $timeout after 2 sec $ionicHistory.backView().stateName
pen.js:59 tabs.fact2
pen.js:56 stateChangeSuccess
pen.js:64 State change from: tabs.fact3 to: tabs.fact2
pen.js:52 $scope.$watch $ionicHistory.backView change detect. newVal:
pen.js:53 tabs.fact1
pen.js:58 $timeout after 2 sec $ionicHistory.backView().stateName
pen.js:59 tabs.fact1

问题

  1. 如何纠正这种行为?也许重写这个委托或以某种方式覆盖它?

  1. How to correct this behavior? Maybe rewrite this delegate or override it somehow?

有解决办法吗?因为我依靠正确的先前状态来显示/隐藏某些东西.

Is there a workaround? As I rely on the correct previous state in order to show/hide something.

JS

angular.module('ionicApp', ['ionic'])

.config(function($stateProvider, $urlRouterProvider) {

  $stateProvider
    .state('tabs', {
      url: "/tab",
      abstract: true,
      templateUrl: "templates/tabs.html",
      controller: "MainCtrl"
    })
    .state('tabs.home', {
      url: "/home",
      views: {
        'home-tab': {
          templateUrl: "templates/home.html",
          controller: 'HomeTabCtrl'
        }
      }
    })
    .state('tabs.fact1', {
      url: "/fact1",
      views: {
        'home-tab': {
          templateUrl: "templates/fact1.html",
          controller: 'Fact1TabCtrl'
        }
      }
    })
    .state('tabs.fact2', {
      url: "/fact2",
      views: {
        'home-tab': {
          templateUrl: "templates/fact2.html",
          controller: 'Fact2TabCtrl'
        }
      }
    })
    .state('tabs.fact3', {
      url: "/fact3",
      views: {
        'home-tab': {
          templateUrl: "templates/fact3.html",
          controller: 'Fact3TabCtrl'
        }
      }
    })
    .state('tabs.about', {
      url: "/about",
      views: {
        'about-tab': {
          templateUrl: "templates/about.html"
        }
      }
    })
    .state('tabs.navstack', {
      url: "/navstack",
      views: {
        'about-tab': {
          templateUrl: "templates/nav-stack.html"
        }
      }
    });


   $urlRouterProvider.otherwise("/tab/home");

})

.controller('MainCtrl', function($scope, $rootScope, $timeout, $ionicHistory) {
    $scope.$watch(function() {
    return $ionicHistory.backView() ? $ionicHistory.backView().stateName : null;
  }, function (newVal, oldVal) {
    console.log('$scope.$watch $ionicHistory.backView change detect. newVal:');
    console.log(newVal);
  });

    $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ 
    console.log('stateChangeSuccess');

    $timeout(function(){ 
      console.log('$timeout after 2 sec $ionicHistory.backView().stateName');
      console.log($ionicHistory.backView().stateName);
    }, 2000);
    });
})

.controller('HomeTabCtrl', function($scope, $rootScope) {
  // console.log('Home');

  $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){ 
    console.log('State change from: ' + fromState.name + ' to: ' + toState.name);
  });
})

.controller('Fact1TabCtrl', function($scope) {
  // console.log('Fact1');
})

.controller('Fact2TabCtrl', function($scope) {
  // console.log('Fact2');
})

.controller('Fact3TabCtrl', function($scope) {
  // console.log('Fact3');
});

HTML

<html ng-app="ionicApp">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

  <title>Navigation Example</title>

  <link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet">
  <script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
</head>

<body>

  <ion-nav-bar class="bar-positive">
    <ion-nav-back-button class="button-icon ion-arrow-left-c">
    </ion-nav-back-button>
  </ion-nav-bar>

  <ion-nav-view></ion-nav-view>


  <script id="templates/tabs.html" type="text/ng-template">
    <ion-tabs class="tabs-icon-top tabs-positive">

      <ion-tab title="Home" icon="ion-home" href="#/tab/home">
        <ion-nav-view name="home-tab"></ion-nav-view>
      </ion-tab>

      <ion-tab title="About" icon="ion-ios-football" href="#/tab/about">
        <ion-nav-view name="about-tab"></ion-nav-view>
      </ion-tab>

      </ion-tab>

    </ion-tabs>
  </script>

  <script id="templates/home.html" type="text/ng-template">
    <ion-view view-title="Home">
      <ion-content class="padding">
        <p>
          <a class="button icon ion-home" href="#/tab/home"> Home</a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact1">
            Fact1
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact2">
            Fact2
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact3">
            Fact3
          </a>
        </p>
      </ion-content>
    </ion-view>
  </script>

  <script id="templates/fact1.html" type="text/ng-template">
    <ion-view view-title="Fact1">
      <ion-content class="padding">
        <p>
          <a class="button icon ion-home" href="#/tab/home"> Home</a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact1">
            Fact1
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact2">
            Fact2
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact3">
            Fact3
          </a>
        </p>
      </ion-content>
    </ion-view>
  </script>

  <script id="templates/fact2.html" type="text/ng-template">
    <ion-view view-title="Fact2">
      <ion-content class="padding">
        <p>
          <a class="button icon ion-home" href="#/tab/home"> Home</a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact1">
            Fact1
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact2">
            Fact2
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact3">
            Fact3
          </a>
        </p>
      </ion-content>
    </ion-view>
  </script>

  <script id="templates/fact3.html" type="text/ng-template">
    <ion-view view-title="Fact3">
      <ion-content class="padding">
        <p>
          <a class="button icon ion-home" href="#/tab/home"> Home</a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact1">
            Fact1
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact2">
            Fact2
          </a>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/fact3">
            Fact3
          </a>
        </p>
      </ion-content>
    </ion-view>
  </script>

  <script id="templates/about.html" type="text/ng-template">
    <ion-view view-title="About">
      <ion-content class="padding">
        <h3>Create hybrid mobile apps with the web technologies you love.</h3>
        <p>Free and open source, Ionic offers a library of mobile-optimized HTML, CSS and JS components for building highly interactive apps.</p>
        <p>Built with Sass and optimized for AngularJS.</p>
        <p>
          <a class="button icon icon-right ion-chevron-right" href="#/tab/navstack">Tabs Nav Stack</a>
        </p>
      </ion-content>
    </ion-view>
  </script>

  <script id="templates/nav-stack.html" type="text/ng-template">
    <ion-view view-title="Tab Nav Stack">
      <ion-content class="padding">
        <p><img src="http://ionicframework.com/img/diagrams/tabs-nav-stack.png" style="width:100%"></p>
      </ion-content>
    </ion-view>
  </script>

</body>

</html>

推荐答案

github上公开的issues中有很多关于历史和导航的问题.

There are a lot of questions about history and navigation among the issues open on github.

我猜导航坏了,需要修复.

I guess the navigation is broken and needs to be fixed.

$ionicHistory 跟踪将每个访问过的视图推入堆栈的视图.实际上那里有2个数组:

$ionicHistory keeps track of the view pushing each visited view on a stack. Actually there are 2 arrays there:

$ionicHistory.viewHistory().views

$ionicHistory.viewHistory().histories

我猜第一个是当前堆栈的视图历史,而第二个考虑所有历史.
不同的导航可以有不同的历史:标签、侧边菜单等,当你从一个历史切换到另一个历史时,Ionic 应该记住每个状态.

I guess the first one is the history of views for the current stack while the second considers all the histories.
Different navigations can have different histories: tabs, sidemenu etc etc, and Ionic should remember each state when you switch from one history to the other.

通读他们的文档,您可以找到:

Reading through their documentation you can find this:

与传统的浏览器环境不同,应用程序和网络应用程序具有平行的独立历史,例如标签.用户应该在一个选项卡上深入浏览几页,然后切换到新选项卡并后退,后退按钮与上一个选项卡无关,而是与在该选项卡中访问过的前几页.

Unlike a traditional browser environment, apps and webapps have parallel independent histories, such as with tabs. Should a user navigate few pages deep on one tab, and then switch to a new tab and back, the back button relates not to the previous tab, but to the previous pages visited within that tab.

您可以在此处找到 currentHistoryId:$ionicHistory.currentHistoryId().

You can find the currentHistoryId here: $ionicHistory.currentHistoryId().

当进入主控制器的视图时,我已经稍微改变了你的示例,显示 2 个数组:

I've changed your example a little bit displaying the 2 arrays when entering the view of the main controller:

.controller('MainCtrl', function($scope, $rootScope, $timeout, $ionicHistory) {
      $scope.$on('$ionicView.enter', function(e) {
        var history = $ionicHistory.viewHistory();
        angular.forEach(history.views, function(view, index){
            console.log('views: ' + view.stateName);
        });
        angular.forEach(history.histories[$ionicHistory.currentHistoryId()].stack, function(view, index){
            console.log('history stack:' + view.stateName);
        });
    });
})

如您所见,第一个数组 views 跟踪您访问过的所有视图.
如果您正在显示您以前访问过的视图,则如果您来回访问不会添加元素.

As you can see, the first array views keeps track of all the views you have visited.
If you go back and forth in doesn't add elements if you are displaying a view you've previously visited.

每个视图都有两个属性:backViewId 和 forwardViewId.当元素添加到集合中时,这两个值似乎是视图的一部分.当您导航时,它们不会改变.

Each view has two properties: backViewId and forwardViewId. These 2 values seems to be part of the view when the elements are added to the collection. They don't change when you navigate.

所以,当你遵循顺序时会发生什么:

So, what happens is when you follow the sequence:

Home -> Fact1 -> Fact2 -> Fact3 -> Fact2

Ionic 在集合中找到视图 Fact2,得到它的 backViewId(它指向 Fact1),这就是它将用作要返回的视图.

Ionic finds the view Fact2 in the collection, gets it's backViewId (which points to Fact1) and that's what it will use as a view to go back to.

我没有在代码中进行一些调试,并试图自己强制查看后视图,但事情变得一团糟.

I didn't some debugging in the code and tried to force the back-view myself but things get messed up.

我猜他们选择了这条路径,因为当你回到根目录时 - 主页 - 后退按钮应该被隐藏.当您按照顺序操作时,事情并没有按预期工作:

I guess they've chosen this path cause when you're back to the root - home - the back button should be hidden. Things don't work as expected when you follow the sequence:

我注意到的另一件事是,有时即使元素已经存在,视图也会添加到此集合中.

Another thing I've noticed is the fact that sometimes views are added to this collection even if the element is already there.

你可以试试这个顺序:

Home -> Fact1 -> Fact2 - Home (button)

您现在可以看到后退按钮(在标题中)告诉您后退视图是 Fact2,实际上控制台显示相同:

As you can see now the back button (in the header) tells you the back view is Fact2 and in fact the console shows the same:

  • 查看:tabs.home
  • 视图:tabs.fact1
  • 视图:tabs.fact2
  • 查看:tabs.home
  • 历史堆栈:tabs.home
  • 历史堆栈:tabs.fact1
  • 历史堆栈:tabs.fact2
  • 历史堆栈:tabs.home

这次出于某种奇怪的原因,向集合中添加了一个新视图,并且常规模式已更改.

For some strange reason this time a new view has been added to the collection and the regular pattern has changed.

这里有一个 codepen 和一些测试.

There's a codepen here with some tests.

相关文章