javascript $ionicHistory.backView 手动进入前一状态时状态不正确
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31364578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
$ionicHistory.backView has incorrect state when go to previous state manually
提问by HP.
I did a small experiment: http://codepen.io/hawkphil/pen/NqMomm?editors=101
我做了一个小实验:http: //codepen.io/hawkphil/pen/NqMomm?editors=101
Here is my state flow (click on the buttons): Home -> Fact1 -> Fact2 -> Fact3 -> Fact2
这是我的状态流(单击按钮): Home -> Fact1 -> Fact2 -> Fact3 -> Fact2
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 MANUALLYby 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.
在每次状态更改时,我都会出现在console.log
for$ionicHistory.backView
但是,您可以看到pen.js:64
,奇怪的事情发生了。$ionicHistory.backView
我app.fact2
从后退按钮进入的“认为”,它显示app.fact1
为以前的状态(行pen.js:53
)。这是不正确的,对吧?它应该显示app.fact3
为以前的状态,因为我必须通过单击按钮手动app.fact2
状态。我还显示了(line )的值,以防万一它很慢。但它仍然是不正确的。$timeout
pen.js:59
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
QUESTION
问题
How to correct this behavior? Maybe rewrite this delegate or override it somehow?
Is there a workaround? As I rely on the correct previous statein order to show/hide something.
如何纠正这种行为?也许重写这个委托或以某种方式覆盖它?
有解决方法吗?因为我依靠正确的先前状态来显示/隐藏某些东西。
JS
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
<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>
回答by LeftyX
There are a lot of questions about history and navigation among the issues open on github.
在github上open的issues中,有很多关于history和navigation的问题。
I guess the navigation is broken and needs to be fixed.
我猜导航坏了,需要修复。
$ionicHistory
keeps track of the view pushing each visited view on a stack.
Actually there are 2 arrays there:
$ionicHistory
跟踪将每个访问过的视图推送到堆栈上的视图。实际上那里有2个数组:
$ionicHistory.viewHistory().views
and
和
$ionicHistory.viewHistory().histories
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.
我猜第一个是当前堆栈的视图历史,而第二个考虑所有历史。
不同的导航可以有不同的历史:选项卡、侧边菜单等,当你从一个历史切换到另一个时,Ionic 应该记住每个状态。
Reading through their documentationyou 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.
与传统浏览器环境不同,应用程序和 Web 应用程序具有平行的独立历史记录,例如选项卡。如果用户在一个选项卡上导航几页深,然后切换到新选项卡并返回,则后退按钮与前一个选项卡无关,而是与该选项卡内访问的前一页相关。
You can find the currentHistoryIdhere: $ionicHistory.currentHistoryId()
.
你可以找到currentHistoryId这里:$ionicHistory.currentHistoryId()
。
I've changed your example a little bit displaying the 2 arrays when entering the view of the main controller:
在进入主控制器的视图时,我对您的示例进行了一些更改,以显示 2 个数组:
.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);
});
});
})
As you can see, the first array viewskeeps 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.
如您所见,第一个数组视图会跟踪您访问过的所有视图。
如果您正在显示您以前访问过的视图,则如果您来回切换不会添加元素。
Each view has two properties: backViewIdand 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.
每个视图都有两个属性:backViewId和forwardViewId。当元素添加到集合中时,这两个值似乎是视图的一部分。当您导航时,它们不会改变。
So, what happens is when you follow the sequence:
因此,当您遵循以下顺序时会发生什么:
Home -> Fact1 -> Fact2 -> Fact3 -> Fact2
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.
IonicFact2
在集合中找到视图,获取它backViewId
(指向Fact1
),这就是它将用作返回的视图。
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.
我注意到的另一件事是,即使元素已经存在,有时也会将视图添加到此集合中。
You can try the sequence:
您可以尝试以下顺序:
Home -> Fact1 -> Fact2 - Home (button)
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:
正如您现在看到的,后退按钮(在标题中)告诉您后视图是 Fact2,实际上控制台显示相同:
- views: tabs.home
- views: tabs.fact1
- views: tabs.fact2
- views: tabs.home
- history stack:tabs.home
- history stack:tabs.fact1
- history stack:tabs.fact2
- history stack:tabs.home
- 视图: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.
这次出于某种奇怪的原因,集合中添加了一个新视图,并且常规模式已更改。
There's a codepenhere with some tests.
这里有一个带有一些测试的代码笔。
回答by aero
My solution/workaround:
我的解决方案/解决方法:
Create an additional state to traverse to that references the same url, templateUrl, and controller.
创建一个额外的状态来遍历引用相同的 url、templateUrl 和控制器。
For example if I have:
例如,如果我有:
$stateProvider.state('fact2', {
url: '/fact2/:factFilter',
templateUrl: 'fact2.html',
controller: 'Fact2Ctrl'
})
$stateProvider.state('fact2', {
url: '/fact2/:factFilter',
templateUrl: 'fact2.html',
controller: 'Fact2Ctrl'
})
Then I also create a "fact2" duplicate with only a different state name
然后我还创建了一个只有不同状态名称的“fact2”副本
$stateProvider.state('fact2_duplicate', {
url: '/fact2/:factFilter',
templateUrl: 'fact2.html',
controller: 'Fact2Ctrl'
})
$stateProvider.state('fact2_duplicate', {
url: '/fact2/:factFilter',
templateUrl: 'fact2.html',
controller: 'Fact2Ctrl'
})
If I am receiving the funny transition behavior, I can call $state.go('fact2_duplicate')
and the history will be more inline to what I am expecting.
如果我收到有趣的过渡行为,我可以打电话$state.go('fact2_duplicate')
,历史将更符合我的期望。
Hope this helps someone.
希望这可以帮助某人。