在 AngularJS 中读取查询参数最简洁的方法是啥?

Posted

技术标签:

【中文标题】在 AngularJS 中读取查询参数最简洁的方法是啥?【英文标题】:What's the most concise way to read query parameters in AngularJS?在 AngularJS 中读取查询参数最简洁的方法是什么? 【发布时间】:2012-06-19 06:59:00 【问题描述】:

我想使用 AngularJS 读取 URL 查询参数的值。我正在使用以下 URL 访问 html

http://127.0.0.1:8080/test.html?target=bob

正如预期的那样,location.search"?target=bob"。 为了访问 target 的值,我在网上找到了各种示例,但它们都不能在 AngularJS 1.0.0rc10 中使用。特别是以下都是undefined

$location.search.target $location.search['target'] $location.search()['target']

有人知道什么会起作用吗? (我使用$location 作为我的控制器的参数)


更新:

我在下面发布了一个解决方案,但我并不完全满意。 Developer Guide: Angular Services: Using $location 的文档说明了以下关于 $location 的内容:

我应该什么时候使用 $location?

任何时候您的应用程序需要对当前的变化做出反应 URL,或者如果您想更改浏览器中的当前 URL。

对于我的场景,我的页面将从带有查询参数的外部网页打开,因此我本身并不是“对当前 URL 的更改做出反应”。所以也许$location 不是适合这项工作的工具(有关丑陋的细节,请参阅下面的答案)。因此,我将这个问题的标题从“如何使用 $location 读取 AngularJS 中的查询参数?”到“在 AngularJS 中读取查询参数最简洁的方法是什么?”。显然,我可以只使用 javascript 和正则表达式来解析 location.search,但是对于如此基本的东西使用低级别确实冒犯了我的程序员的敏感性。

那么:有没有比我在回答中使用$location 更好的方法,还是有更简洁的替代方法?

【问题讨论】:

不应该 $location.search()['target'] 工作吗? 这个不行,因为路径后面没有hash。 http://127.0.0.1:8080/test.html#?target=bob 会起作用,注意#? 之前。 $location 是二级路由方法,不会发送到服务器。 @DanielF @rob,你们都是对的。 $location.search()['target'] 在现代浏览器中调用 $locationProvider.html5Mode(true) 后有效。 【参考方案1】:

您可以将$routeParams(需要ngRoute)注入您的控制器。这是文档中的一个示例:

// Given:
// URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
// Route: /Chapter/:chapterId/Section/:sectionId
//
// Then
$routeParams ==> chapterId:1, sectionId:2, search:'moby'

编辑:您还可以使用$location 服务(在ng 中提供)获取和设置查询参数,尤其是它的search 方法:$location.search()。

$routeParams 在控制器初始加载后就没那么有用了; $location.search()可以随时拨打。

【讨论】:

感谢您的建议和链接!我阅读了该页面并尝试设置一个工作示例。但是,这种方法对我不起作用,因为在这种情况下我真的不想使用路由。尽管如此,这是一个有用的建议,一旦我有足够的 *** 代表,我会支持它。 我想说@pkozlowski.opensource 的答案在这种情况下更准确 不完全......查询参数包含在 $routeParams 对象中,具有正常的路由参数。您可以使用 $location.search() 读取/设置它们。我会将其添加到答案中。 Jakub 是对的。它们是不同的东西。当您在 Angular 中使用“搜索”时,它会将查询附加到散列(URL 的末尾)。 URI 的 RFC 规范声明查询参数应该预先(而不是附加)散列。因此,“搜索”是一个只有角度才能推断和解释的结构。这就是为什么只有 HTML5 模式适用于上述解决方案,因为无论实际 URI 是什么,您都将所有请求委托给一个页面(在服务器级别)。 这只有在你想在 angularJS 中使用路由时才有效!【参考方案2】:

为了部分回答我自己的问题,这里是 HTML5 浏览器的工作示例:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
  <script src="http://code.angularjs.org/1.0.0rc10/angular-1.0.0rc10.js"></script>
  <script>
    angular.module('myApp', [], function($locationProvider) 
      $locationProvider.html5Mode(true);
    );
    function QueryCntl($scope, $location) 
      $scope.target = $location.search()['target'];
    
  </script>
</head>
<body ng-controller="QueryCntl">

Target: target<br/>

</body>
</html>

关键是如上所述调用$locationProvider.html5Mode(true);。现在打开http://127.0.0.1:8080/test.html?target=bob 时可以使用。我对它无法在旧版浏览器中运行这一事实感到不高兴,但无论如何我可能会使用这种方法。

一种适用于旧版浏览器的替代方法是放弃html5mode(true) 调用并使用以下地址和哈希+斜杠:

http://127.0.0.1:8080/test.html#/?target=bob

相关文档位于Developer Guide: Angular Services: Using $location(奇怪的是我的谷歌搜索没有找到这个......)。

【讨论】:

谢谢。我一直在努力阅读查询参数。如上所述,不断得到“未定义”。将模式设置为 html5 有效。 &lt;body&gt;ng-controller属性不应该设置为MyApp吗? 看起来从 Angular 1.3 开始,为了使用 html5Mode,您还需要添加 &lt;base href="/" /&gt; 标记,或者添加 requireBase: false 作为调用 html5Mode 的另一个参数。 Details here【参考方案3】:

很好,您已经设法让它在 html5 模式下工作,但也可以让它在 hashbang 模式下工作。

你可以简单地使用:

$location.search().target

访问“目标”搜索参数。

作为参考,这里是工作的 jsFiddle:http://web.archive.org/web/20130317065234/http://jsfiddle.net/PHnLb/7/

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $location) 

    $scope.location = $location;
    $scope.$watch('location.search()', function() 
        $scope.target = ($location.search()).target;
    , true);

    $scope.changeTarget = function(name) 
        $location.search('target', name);
    
<div ng-controller="MyCtrl">

    <a href="#!/test/?target=Bob">Bob</a>
    <a href="#!/test/?target=Paul">Paul</a>
    
    <hr/>    
    URL 'target' param getter: target<br>
    Full url: location.absUrl()
    <hr/>
    
    <button ng-click="changeTarget('Pawel')">target=Pawel</button>
    
</div>

【讨论】:

你需要 $location.search() 周围的括号吗? @Magne:是的,你需要括号,$location.search 是一个方法docs.angularjs.org/api/ng/service/$location 不要忘记,如果您不使用HTML5Mode(true),那么只有#/ 之后的参数可用,或者添加到以#/ 开头的url。 @nandin:不,你确实不需要需要括号围绕 $location.search()。我不确定为什么这个答案会把他们放在那里。 我觉得@nandin 误解了“你需要括号”的问题。您确实在搜索后需要括号,但不是整个 $location.search() 周围的括号。【参考方案4】:

你也可以使用 $location.$$search.yourparameter

【讨论】:

$$search 是一个内部变量,使用它不是一个好主意。【参考方案5】:

只是为了总结一下。

如果您的应用程序是从外部链接加载的,那么 Angular 不会将此检测为 URL 更改,因此 $loaction.search() 会给您一个空对象。要解决这个问题,您需要在您的应用配置(app.js)中设置以下内容

.config(['$routeProvider', '$locationProvider', function ($routeProvider,     $locationProvider) 

   $routeProvider
      .when('/', 
         templateUrl: 'views/main.html',
         controller: 'MainCtrl'
      )
      .otherwise(
         redirectTo: '/'
      );

      $locationProvider.html5Mode(true);
 ]);

【讨论】:

是的。这是一个痛苦的发现。感谢您的评论。【参考方案6】:

$location.search() 仅适用于打开 HTML5 模式且仅在支持浏览器的情况下。

这将永远有效:

$window.location.search

【讨论】:

【参考方案7】:

可以通过两种方式完成:

    使用$routeParams

最佳和推荐的解决方案是在您的控制器中使用$routeParams。 它需要安装ngRoute 模块。

   function MyController($scope, $routeParams) 
      // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
      // Route: /Chapter/:chapterId/Section/:sectionId
      // $routeParams ==> chapterId:'1', sectionId:'2', search:'moby'
      var search = $routeParams.search;
  
    使用$location.search()

这里有一个警告。它仅适用于 HTML5 模式。默认情况下,它不适用于其中没有 hash(#) 的 URL http://localhost/test?param1=abc&amp;param2=def

您可以通过在 URL 中添加 #/ 来使其工作。 http://localhost/test#/?param1=abc&amp;param2=def

$location.search() 返回一个像这样的对象:


  param1: 'abc',
  param2: 'def'

【讨论】:

感谢您对#/的建议【参考方案8】:

只是对 Ellis Whitehead 的回答的精确。如果不使用 &lt;base href=""&gt; 标签指定应用程序的基本 URL 或将参数 requireBase 设置为 false$locationProvider.html5Mode(true); 将无法与新版本的 angularjs 一起使用。

From the doc:

如果您将 $location 配置为使用 html5Mode (history.pushState),您需要使用标签指定应用程序的基本 URL,或者通过将带有 requireBase:false 的定义对象传递给$locationProvider.html5Mode():

$locationProvider.html5Mode(
  enabled: true,
  requireBase: false
);

【讨论】:

【参考方案9】:

有点晚了,但我认为您的问题是您的网址。如果不是

http://127.0.0.1:8080/test.html?target=bob

你有

http://127.0.0.1:8080/test.html#/?target=bob

我很确定它会奏效。 Angular 对它的 #/

真的很挑剔

【讨论】:

仅当您未启用 HTML5 模式时。 #/ 并不总是存在于 Angular 网址中。 如果您正在构建一个 SPA。我所有的网址都有一个#。 HTML5Mode 意味着 1) 页面刷新时出现 404 和 2) 直接 url 不起作用。似乎要付出高昂的代价。【参考方案10】:

我发现对于一个 SPA HTML5Mode 会导致很多 404 错误问题,在这种情况下没有必要让 $location.search 工作。就我而言,我想在用户访问我的网站时捕获 URL 查询字符串参数,无论他们最初链接到哪个“页面”,并且能够在他们登录后将它们发送到该页面。所以我只捕获所有app.run 中的那些东西

$rootScope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) 
    if (fromState.name === "") 
        e.preventDefault();
        $rootScope.initialPage = toState.name;
        $rootScope.initialParams = toParams;
        return;
    
    if ($location.search().hasOwnProperty('role')) 
        $rootScope.roleParameter = $location.search()['role'];
    
    ...

然后登录后我可以说 $state.go($rootScope.initialPage, $rootScope.initialParams)

【讨论】:

以上是关于在 AngularJS 中读取查询参数最简洁的方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS:从控制器内读取路由参数

编写此查询以将小时添加到日期的最简洁方法

使用Getopt :: Long解析参数的最简洁方法

如何使用 AngularJS 的 ui-router 提取查询参数?

在 C 中读取和打印 .txt 文件行的最清晰方法

使用 XPath 从参数映射构建 URL 查询字符串