Angular JS:URL 参数出现在"#!/"之前,不会出现在 $location.search() 中



我正在将其他人制作的小型现有Angular JS应用程序集成到一个不是使用Angular构建的现有网站中。

所有 Angular JS 应用程序文件都保存在一个完全独立的目录中,然后用户可以单击链接将它们带到该子目录的索引。例如:

<a href="/path/to/angular-app/?returnUrl=/original/location">Login.</a>

正如你在上面看到的,我需要传递一个名为returnUrl的 URL 参数。然后,我需要在 Angular JS 应用程序中选取此值,使用:

$location.search()

但是,这实际上返回一个空对象。我认为这是因为 Angular JS 在 URL 参数之后的 URL 上附加了#!/login,如下所示:

example.com/path/to/app?returnUrl=/original/location/#!/login

如果我在浏览器中修改 URL,将returnUrl参数移动到 URL 的末尾并刷新页面,它可以工作并且$location.search()返回{returnUrl: "/original/location/"}.但是,据我所知,我无法在我的网站中更改它,因为该参数是指向 Angular JS 应用程序的链接的一部分,之后会自动添加#!/login

我是新的AngularJS,所以请尽可能清楚地解释:

  1. 这是怎么回事?为什么 URL 参数在#!/login之前
  2. 为什么这会阻止$location.search()返回任何内容?如果我将参数移动到生成的 URL 的末尾,它可以工作。
  3. 我该怎么做才能解决这个问题?
这是

怎么回事?为什么 URL 参数在 #!/login 之前?

您可以将#! 之前的查询字符串参数视为服务器端参数,将#!之后的查询字符串参数视为客户端参数。这是完全有效的:

http://example.com?serverParam=client1#!angularRoute?angularParam=someValue

服务器端参数允许您配置如何从服务器提供页面,然后在提供服务器页面并加载 Angular 应用程序后,使用客户端参数提供特定 Angular 应用程序所期望的内容。

为什么这会阻止 $location.search() 返回任何内容?如果我 将参数移动到生成的 URL 的末尾,它有效。

因为在您将值移动到客户端参数之前,没有为客户端参数指定任何内容。

我该怎么做才能解决这个问题?

  1. 您可以将链接更改为与修改它们以使其工作的方式相同:<a href="example.com/path/to/app/#!/login?returnUrl=/original/location">Login.</a>或复制参数,使其在服务器和客户端上都可用<a href="example.com/path/to/app/?returnUrl=/original/location#!/login?returnUrl=/original/location">Login.</a>
  2. 您可以注入$window并从$window.location.search
  3. 您可以注入$location并使用$location.absUrl()

下面是如何从服务器端参数设置客户端参数的示例:

var app = angular.module('YOURAPPNAME', []);
app.run(['$location', function($location) {
// I'm going to fake out the url so it runs in the SnippetEditor.
var url = "example.com/path/to/app?returnUrl=/original/location/#!/login"; //$location.absUrl();
var hashbangIdx = url.indexOf('#!');
var serverStr = hashbangIdx > -1 ? url.substring(0, hashbangIdx) : url;
var qIdx = serverStr.indexOf("?");
var p = qIdx > -1 ? serverStr.substring(qIdx).split(/[&||?]/) : [];
for (var i = 0; i < p.length; i += 1) {
if (p[i].indexOf('=') > -1) {
var param = p[i].split('=');
$location.search(param[0], param[1]);
}
}
}]);
app.controller('MainCtrl', ['$scope', '$location', function($scope, $location) {
$scope.params = $location.search();
}]);
<!DOCTYPE html>
<html ng-app="YOURAPPNAME">
<head>
<meta charset="utf-8" />
<title>AngularJS</title>
<script data-require="angular.js@1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<h4>Parameters:</h4>
<p ng-repeat="(name, val) in params">
{{name}}: {{val}}
</p>
</body>
</html>

你只需要使用window.location.search

> window.location.search
> "?returnUrl=/original/location/"

仅当您的路由定义了值时,$location.search()才会为您提供值。

以下是您问题的答案:

1) AngularJS 在加载页面的 url 末尾附加 #。因此,如果加载页面的 url 已经具有 returnUrl 的查询参数(似乎是这种情况),它将始终显示在 # 的左侧。

2)一个AngularJS应用程序,一般只关心url中#后面发生什么。AngularJS使用它在状态和更多类似的东西之间路由和传递查询参数。$location.search() 用于检索 # 之后的所有查询参数。

3)这是提取#之前出现的查询参数的方法

function getParamFromURL (paramName) {
var searchStr = window.location.search.substring(1);
var keyValues = searchStr.split('&');
for(var i=0; i<keyValues.length; i++) {
var split = keyValues[i].split('=');
if(split[0] === paramName) {
return decodeURIComponent(split[1]);
}
}
}
var value = getParamFromURL('returnUrl');
console.log(value);

您在 url 中看到的#实际上是所谓的锚链接或片段。通常通过其 id 跳转到特定元素,例如,如果您有一个与此 id 匹配的元素,则导航单击<a href="#footer">将直接滚动您的页面。

Angular 和其他框架(如 React)利用此功能通过使用哈希作为当前活动路由来创建所谓的哈希路由。这样做的好处是它将允许非常快速的设置,并且可以在非HTML5浏览器上开箱即用。

关于为什么查询参数在哈希之前,这只是因为这实际上是您在链接中指定的。Angular 将您正在加载的 url 视为项目的根目录,并在初始化后与当前路由器添加自己的#。您可能有一个服务器仅在指定此查询参数时为 Angular 应用程序提供服务,因此保持它就位非常重要。如果查询参数放在哈希之后,则将其视为 Angular 应用路由的一部分,因此在调用$location.search()时返回。

我建议您做的是在链接中明确指定#,或者使用 html5 模式。Html5模式意味着你不会在你的URL中获得哈希形式,而是那些不那么丑陋的"普通"形式。

为此,您必须在应用程序中启用 html5 模式,

.config(function ($locationProvider) {
$locationProvider.html5Mode(true);
}

并在脑海中添加元基础

<base href="/" />

问题是,现在,如果您尝试加载一个不是主页的页面,您将遇到 404 问题。

为了防止这种情况,您必须为应用程序的每个子路由提供 Angular 条目。有多种方法,具体取决于您在服务器上使用/想要使用的内容。这是展示其中大多数的 Angular 常见问题解答。

您可以使用 $location.absUrl() :它将返回完整的URL,其中所有段都根据RFC 3986中指定的规则进行编码。

var resultURl = GetURLParameter('returnUrl');
console.log(resultURl);
function GetURLParameter(param) {
// var URL =  $location.absUrl();
var URL = "example.com/path/to/app?returnUrl=/original/location/#!/login";
var allVariables = URL.split('?');
for (var i = 0; i < allVariables.length; i++) {
var paramName = allVariables[i].split('=');
if (paramName[0] == param) {
return paramName[1].split("#")[0];
}
}
}

====

==================================================================RouteProviderrouteParams将适用于您的情况。

您可以将returnUrl作为路由参数传递到路由中,并使用$routeParams.returnUrl返回控制器。

我该怎么做才能解决这个问题?

您可以尝试此方法来解决此问题。

.HTML:

<a href="#login/original/location">Login Return Url</a>

路由文件 :

$routeProvider.when('/login/:returnUrl', {
templateUrl: 'partials/partial.html',    
controller: 'MyCtrl'
});

在控制器中,注入$routeParams

.controller('MyCtrl', ['$scope','$routeParams', function($scope, $routeParams) {
var url = $routeParams.returnUrl;
}]);

注意:

如果您使用的是ngRoute,则可以将$routeParams注入控制器。

如果您使用的是angular-ui-router,则可以将$stateParams注入控制器。

检查一下,

function getValue(key, url) {
var regex = new RegExp("[?&]" + key + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
return results[2];
}
var value = getValue("returnUrl","example.com/path/to/app?returnUrl=/original/location/#!/login");
console.log(value);

最新更新