Angular ngRoute/UI-Router 奇怪的重定向行为
Angular ngRoute/UI-Router strange redirect behaviour
我有一个 angular 应用程序,它由一个 index.html 页面组成,里面有一些部分视图。假设有 4 个局部视图:view1、view2、view3 和 view4。当您第一次点击我的 home/root 页面时,我希望 View1 成为加载到 index.html 中的基本视图。我通过将我的 $urlRouterProvider.otherwise()
设置为我的 view1 部分来做到这一点。
出于某种原因,此问题仅针对特定视图发生。假设它是view3。当我单击 view3 上的按钮时,它应该路由到另一个视图,比如 view4。它总是第一次成功路由。但是,每当我通过任何方法 return 到 view3 并尝试在第一个之后的任何时间路由到 view4 时,它总是强制路由回到 $urlRouterProvider.otherwise()
中的任何视图:在这种情况下它是 view1。也不只是 view4。无论我尝试从 view3 路由到哪个视图,它都会在第一次成功加载该视图,然后在它始终默认为 $urlRouterProvider.otherwise()
视图后的任何时间加载。
更奇怪的是,即使它强制路由到 otherwise(),我知道我试图路由到的任何部分的 controller/view 正在加载。如果我将 $urlRouterProvider.otherwise()
设置为我的应用程序中不存在的路由,然后重现这种奇怪的行为,结果是 url 显示为 'localhost:8080/routeThatDoesNotExist',但实际上是什么屏幕上显示的是我试图路由到的视图。这是我的代码的简洁版本:
app.js:
var app = angular.module('app', ['ui.router', 'controllers','services']);
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider.
state('root', {
url: "/",
templateUrl: 'partials/view1.html',
controller: 'View1Ctrl',
}).
state('view2', {
url: "/view2",
controller: 'View2Ctrl',
templateUrl: 'partials/view2.html'
}).
state('view3', {
url: "/view3",
controller: 'View3Ctrl',
templateUrl: 'partials/view3.html',
}).
state('view4', {
url: "/view4",
templateUrl: 'partials/view4.html',
controller: 'View4Ctrl',
});
//more views omitted for brevity...
$locationProvider.html5Mode(true);
}]);
Index.html
<!doctype html>
<html ng-app="app">
<head>
<base href="/">
<title>App</title>
<link rel="...">
<style>...</style>
</head>
<body>
<div ng-controller="IndexDotHtmlCtrl">
<button ui-sref="root">View1</button>
<button ui-sref="view2">View2</button>
<button ui-sref="view3">View3</button>
<div ui-view></div>
</div>
<script src="..."></script>
</body>
</html>
View3.html
<div>
<button ng-click="stateGo()">Go To Another View</button>
</div>
Controllers.js
var controllers = angular.module('controllers', []);
controllers.controller('IndexDotHtmlCtrl', ['$scope', function($scope) {
//code omitted...
}]);
controllers.controller('View1Ctrl', ['$scope', '$state', function($scope, $state) {
//code omitted...
}]);
controllers.controller('View2Ctrl', ['$scope', '$state', function($scope, $state) {
//code omitted...
}]);
controllers.controller('View3Ctrl', ['$scope', '$state', function($scope, $state) {
$scope.stateGo = function() {
$state.go('view4');
}
//more code omitted...
}]);
controllers.controller('View4Ctrl', ['$scope', '$state', 'SomeSvc', function($scope, $state, SomeSvc) {
$scope.RESTful_DATA = SomeSvc.query(); //using ngResource
//more code omitted...
}]);
我尝试做的事情: 我最初使用 Angular 的 ngRoute 遇到这个问题,所以我将我的整个应用程序移到了 Angular UI-路由器问题仍然存在。
认为 $locationProvider 和 html5Mode 可能与此有关。删除了将 # 添加到我的 url 的那些。问题仍然存在。
总而言之,问题是,每当我尝试专门从 view3 路由到我的应用程序中的任何其他视图时,它总是在第一次工作。之后的任何时候,它都会调用 $urlRouterProvider.otherwise()
方法并强制将我重定向到我在其中定义的任何视图。我不确定此时该做什么。谁能帮我弄清楚为什么会出现这种奇怪的路由行为?
在研究了 Whosebug 和 github 之后,我发现问题与 ngRoute/Ui-router 服务本身无关。问题在于我在项目中使用的 <uib-tabset>
和 <uib-accordion>
指令模板。它们是 Angular Ui-Bootstrap 库的一部分。这是一个已知问题,已在 Angular Ui-bootstrap 的 github 上多次提出:例如 here.
如果我理解正确的话,本质上发生的事情是这些 <uib-tabset>
和 <uib-accordion>
获得 <a>
附加到它们的锚标记。这意味着,如果您的 tabset 或手风琴中有任何可点击的元素(基本上,纯文本以外的任何元素),angular 永远不会收到它们的点击事件。它们被浏览器拦截,导致奇怪的重定向行为发生。这解释了为什么我只有特定视图的奇怪路由行为,而不是我应用程序中的所有视图。
Angular Ui-Bootstrap 团队 here 提出的当前修复(向下滚动几格,在屏幕右下角附近查看 'Known Issues' header 并阅读该部分)是修改 tabset 和 accordion 指令模板本身,将它们插入 <a>
锚标记的位置更改为 <div>
标记。这样做会导致您丢失大部分关联的 CSS 样式,因为它们基于 <a>
元素。从这里,只需转到您的 bootstrap.css,找到所有影响 uib-tab 和 uib-accordion 的 CSS 规则,然后更新它们,使它们指向 div 而不是一.
我有一个 angular 应用程序,它由一个 index.html 页面组成,里面有一些部分视图。假设有 4 个局部视图:view1、view2、view3 和 view4。当您第一次点击我的 home/root 页面时,我希望 View1 成为加载到 index.html 中的基本视图。我通过将我的 $urlRouterProvider.otherwise()
设置为我的 view1 部分来做到这一点。
出于某种原因,此问题仅针对特定视图发生。假设它是view3。当我单击 view3 上的按钮时,它应该路由到另一个视图,比如 view4。它总是第一次成功路由。但是,每当我通过任何方法 return 到 view3 并尝试在第一个之后的任何时间路由到 view4 时,它总是强制路由回到 $urlRouterProvider.otherwise()
中的任何视图:在这种情况下它是 view1。也不只是 view4。无论我尝试从 view3 路由到哪个视图,它都会在第一次成功加载该视图,然后在它始终默认为 $urlRouterProvider.otherwise()
视图后的任何时间加载。
更奇怪的是,即使它强制路由到 otherwise(),我知道我试图路由到的任何部分的 controller/view 正在加载。如果我将 $urlRouterProvider.otherwise()
设置为我的应用程序中不存在的路由,然后重现这种奇怪的行为,结果是 url 显示为 'localhost:8080/routeThatDoesNotExist',但实际上是什么屏幕上显示的是我试图路由到的视图。这是我的代码的简洁版本:
app.js:
var app = angular.module('app', ['ui.router', 'controllers','services']);
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider',
function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise("/");
$stateProvider.
state('root', {
url: "/",
templateUrl: 'partials/view1.html',
controller: 'View1Ctrl',
}).
state('view2', {
url: "/view2",
controller: 'View2Ctrl',
templateUrl: 'partials/view2.html'
}).
state('view3', {
url: "/view3",
controller: 'View3Ctrl',
templateUrl: 'partials/view3.html',
}).
state('view4', {
url: "/view4",
templateUrl: 'partials/view4.html',
controller: 'View4Ctrl',
});
//more views omitted for brevity...
$locationProvider.html5Mode(true);
}]);
Index.html
<!doctype html>
<html ng-app="app">
<head>
<base href="/">
<title>App</title>
<link rel="...">
<style>...</style>
</head>
<body>
<div ng-controller="IndexDotHtmlCtrl">
<button ui-sref="root">View1</button>
<button ui-sref="view2">View2</button>
<button ui-sref="view3">View3</button>
<div ui-view></div>
</div>
<script src="..."></script>
</body>
</html>
View3.html
<div>
<button ng-click="stateGo()">Go To Another View</button>
</div>
Controllers.js
var controllers = angular.module('controllers', []);
controllers.controller('IndexDotHtmlCtrl', ['$scope', function($scope) {
//code omitted...
}]);
controllers.controller('View1Ctrl', ['$scope', '$state', function($scope, $state) {
//code omitted...
}]);
controllers.controller('View2Ctrl', ['$scope', '$state', function($scope, $state) {
//code omitted...
}]);
controllers.controller('View3Ctrl', ['$scope', '$state', function($scope, $state) {
$scope.stateGo = function() {
$state.go('view4');
}
//more code omitted...
}]);
controllers.controller('View4Ctrl', ['$scope', '$state', 'SomeSvc', function($scope, $state, SomeSvc) {
$scope.RESTful_DATA = SomeSvc.query(); //using ngResource
//more code omitted...
}]);
我尝试做的事情: 我最初使用 Angular 的 ngRoute 遇到这个问题,所以我将我的整个应用程序移到了 Angular UI-路由器问题仍然存在。
认为 $locationProvider 和 html5Mode 可能与此有关。删除了将 # 添加到我的 url 的那些。问题仍然存在。
总而言之,问题是,每当我尝试专门从 view3 路由到我的应用程序中的任何其他视图时,它总是在第一次工作。之后的任何时候,它都会调用 $urlRouterProvider.otherwise()
方法并强制将我重定向到我在其中定义的任何视图。我不确定此时该做什么。谁能帮我弄清楚为什么会出现这种奇怪的路由行为?
在研究了 Whosebug 和 github 之后,我发现问题与 ngRoute/Ui-router 服务本身无关。问题在于我在项目中使用的 <uib-tabset>
和 <uib-accordion>
指令模板。它们是 Angular Ui-Bootstrap 库的一部分。这是一个已知问题,已在 Angular Ui-bootstrap 的 github 上多次提出:例如 here.
如果我理解正确的话,本质上发生的事情是这些 <uib-tabset>
和 <uib-accordion>
获得 <a>
附加到它们的锚标记。这意味着,如果您的 tabset 或手风琴中有任何可点击的元素(基本上,纯文本以外的任何元素),angular 永远不会收到它们的点击事件。它们被浏览器拦截,导致奇怪的重定向行为发生。这解释了为什么我只有特定视图的奇怪路由行为,而不是我应用程序中的所有视图。
Angular Ui-Bootstrap 团队 here 提出的当前修复(向下滚动几格,在屏幕右下角附近查看 'Known Issues' header 并阅读该部分)是修改 tabset 和 accordion 指令模板本身,将它们插入 <a>
锚标记的位置更改为 <div>
标记。这样做会导致您丢失大部分关联的 CSS 样式,因为它们基于 <a>
元素。从这里,只需转到您的 bootstrap.css,找到所有影响 uib-tab 和 uib-accordion 的 CSS 规则,然后更新它们,使它们指向 div 而不是一.