Angular JS: URL 参数出现在 `#!/` 之前并且没有出现在 $location.search()
Angular JS: URL parameter appears before the `#!/` and doesn't appear in $location.search()
我正在将一个由其他人制作的小型现有 Angular JS 应用程序集成到一个不是用 Angular 构建的现有网站中。
所有 Angular JS 应用程序文件都保存在一个完全独立的目录中,然后用户可以单击 link 将它们带到该子目录的索引中。例如:
<a href="/path/to/angular-app/?returnUrl=/original/location">Login.</a>
正如您在上面看到的,我需要传递一个名为 returnUrl
的 URL 参数。然后我需要在 Angular JS 应用程序中获取这个值,使用:
$location.search()
然而,这实际上returns一个空对象。我认为这是因为 Angular JS 在 URL URL 参数之后附加 #!/login
,像这样:
example.com/path/to/app?returnUrl=/original/location/#!/login
如果我在浏览器中修改 URL,将 returnUrl
参数移动到 URL 的末尾并刷新页面,它会起作用 $location.search()
returns {returnUrl: "/original/location/"}
。但是,据我所知,我无法在我的网站上更改它,因为该参数是 link 到 Angular JS 应用程序的一部分,并且 #!/login
是之后自动添加的.
我是新手AngularJS,所以请尽可能解释清楚:
- 这是怎么回事?为什么 URL 参数 在 之前
#!/login
?
- 为什么这会阻止
$location.search()
返回任何内容?如果我将参数移动到结果 URL 的末尾,它就可以工作。
- 我该怎么做才能解决这个问题?
以下是您问题的答案:
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 中看到的 #
实际上就是所谓的锚点 link 或片段。通常通过其 id 跳转到特定元素,例如导航单击 <a href="#footer">
将直接滚动您的页面,如果您有与此 id 匹配的元素。
Angular 和其他框架,如 React,利用此功能通过使用哈希作为当前活动路由来创建所谓的哈希路由。这样做的好处是它可以进行非常快速的设置,并且可以在非 HTML5 浏览器上开箱即用。
关于为什么查询参数在散列之前,只是因为那实际上是您在 link 中指定的。 Angular 将您正在加载的 url 视为项目的根,并在初始化后将其自己的 #
添加到当前路由器。您可能有一个服务器仅在指定此查询参数时为 Angular 应用程序提供服务,因此保持它的重要性。如果查询参数位于散列之后,它被视为 Angular 应用程序路由的一部分,因此在您调用 $location.search()
.
时返回
我建议您在 link 中明确指定 #
,或者使用 html5 模式。 Html5 模式意味着您不会在 url 中获得散列形式,而是 "normal" 不那么难看的散列形式。
为此,您必须在您的应用中启用 html5 模式,
.config(function ($locationProvider) {
$locationProvider.html5Mode(true);
}
并在你的头脑中添加元基础
<base href="/" />
现在的问题是,如果您尝试加载不是主页的页面,就会遇到 404 问题。
为防止这种情况发生,您必须为应用程序的每个子路径提供 Angular 条目。有多种方法,具体取决于您在服务器上使用/想要使用的内容。 the Angular FAQ 展示了其中的大部分内容。
您可以使用 $location.absUrl() : 它将 return 完整 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];
}
}
}
================================ 或 ==== ================================
RouteProvider
和 routeParams
将适用于您的情况。
您可以在路由中将 returnUrl
作为路由参数传递,然后使用 $routeParams.returnUrl
返回控制器。
What can I do to fix this?
您可以试试这个方法来解决这个问题。
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);
你只需要使用window.location.search
> window.location.search
> "?returnUrl=/original/location/"
$location.search()
仅当您的路线定义了它时才会给您值。
What is going on here? And why is the URL parameter before the #!/login?
你可以把#!前面的querystring参数想成服务器端参数,[=44之后的querystring参数=]#! 作为 客户端 参数。这是完全有效的:
http://example.com?serverParam=client1#!angularRoute?angularParam=someValue
服务器端 参数允许您配置如何从服务器提供页面,然后,一旦提供服务器页面并加载 Angular 应用程序,使用 客户端 参数来提供特定 Angular 应用程序所期望的内容。
Why does this prevent $location.search() from returning anything? If I
move the param to the end of the resulting URL, it works.
因为在您将值移到那里之前,没有为 客户端 参数指定任何内容。
What can I do to fix this?
- 您可以将链接更改为您修改它们以使其正常工作的方式:
<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>
- 您可以注入
$window
并从中获取 服务器端 值
$window.location.search
- 您可以注入
$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>
我正在将一个由其他人制作的小型现有 Angular JS 应用程序集成到一个不是用 Angular 构建的现有网站中。
所有 Angular JS 应用程序文件都保存在一个完全独立的目录中,然后用户可以单击 link 将它们带到该子目录的索引中。例如:
<a href="/path/to/angular-app/?returnUrl=/original/location">Login.</a>
正如您在上面看到的,我需要传递一个名为 returnUrl
的 URL 参数。然后我需要在 Angular JS 应用程序中获取这个值,使用:
$location.search()
然而,这实际上returns一个空对象。我认为这是因为 Angular JS 在 URL URL 参数之后附加 #!/login
,像这样:
example.com/path/to/app?returnUrl=/original/location/#!/login
如果我在浏览器中修改 URL,将 returnUrl
参数移动到 URL 的末尾并刷新页面,它会起作用 $location.search()
returns {returnUrl: "/original/location/"}
。但是,据我所知,我无法在我的网站上更改它,因为该参数是 link 到 Angular JS 应用程序的一部分,并且 #!/login
是之后自动添加的.
我是新手AngularJS,所以请尽可能解释清楚:
- 这是怎么回事?为什么 URL 参数 在 之前
#!/login
? - 为什么这会阻止
$location.search()
返回任何内容?如果我将参数移动到结果 URL 的末尾,它就可以工作。 - 我该怎么做才能解决这个问题?
以下是您问题的答案:
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 中看到的 #
实际上就是所谓的锚点 link 或片段。通常通过其 id 跳转到特定元素,例如导航单击 <a href="#footer">
将直接滚动您的页面,如果您有与此 id 匹配的元素。
Angular 和其他框架,如 React,利用此功能通过使用哈希作为当前活动路由来创建所谓的哈希路由。这样做的好处是它可以进行非常快速的设置,并且可以在非 HTML5 浏览器上开箱即用。
关于为什么查询参数在散列之前,只是因为那实际上是您在 link 中指定的。 Angular 将您正在加载的 url 视为项目的根,并在初始化后将其自己的 #
添加到当前路由器。您可能有一个服务器仅在指定此查询参数时为 Angular 应用程序提供服务,因此保持它的重要性。如果查询参数位于散列之后,它被视为 Angular 应用程序路由的一部分,因此在您调用 $location.search()
.
我建议您在 link 中明确指定 #
,或者使用 html5 模式。 Html5 模式意味着您不会在 url 中获得散列形式,而是 "normal" 不那么难看的散列形式。
为此,您必须在您的应用中启用 html5 模式,
.config(function ($locationProvider) {
$locationProvider.html5Mode(true);
}
并在你的头脑中添加元基础
<base href="/" />
现在的问题是,如果您尝试加载不是主页的页面,就会遇到 404 问题。
为防止这种情况发生,您必须为应用程序的每个子路径提供 Angular 条目。有多种方法,具体取决于您在服务器上使用/想要使用的内容。 the Angular FAQ 展示了其中的大部分内容。
您可以使用 $location.absUrl() : 它将 return 完整 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];
}
}
}
================================ 或 ==== ================================
RouteProvider
和 routeParams
将适用于您的情况。
您可以在路由中将 returnUrl
作为路由参数传递,然后使用 $routeParams.returnUrl
返回控制器。
What can I do to fix this?
您可以试试这个方法来解决这个问题。
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);
你只需要使用window.location.search
> window.location.search
> "?returnUrl=/original/location/"
$location.search()
仅当您的路线定义了它时才会给您值。
What is going on here? And why is the URL parameter before the #!/login?
你可以把#!前面的querystring参数想成服务器端参数,[=44之后的querystring参数=]#! 作为 客户端 参数。这是完全有效的:
http://example.com?serverParam=client1#!angularRoute?angularParam=someValue
服务器端 参数允许您配置如何从服务器提供页面,然后,一旦提供服务器页面并加载 Angular 应用程序,使用 客户端 参数来提供特定 Angular 应用程序所期望的内容。
Why does this prevent $location.search() from returning anything? If I move the param to the end of the resulting URL, it works.
因为在您将值移到那里之前,没有为 客户端 参数指定任何内容。
What can I do to fix this?
- 您可以将链接更改为您修改它们以使其正常工作的方式:
<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>
- 您可以注入
$window
并从中获取 服务器端 值$window.location.search
- 您可以注入
$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>