【问题标题】:angular.js link behaviour - disable deep linking for specific URLsangular.js 链接行为 - 禁用特定 URL 的深度链接
【发布时间】:2012-07-19 18:27:08
【问题描述】:

我有一个启用了 HTML5 模式的 Angular.js 应用程序。

$location.Html5mode(true).hashbang("!");

我想要实现的是获取一些 URL 或 <a> 标签来执行正常的浏览行为,而不是使用 HTML5 历史 API 更改地址栏中的 URL 并使用 Angular 控制器处理它。

我有这个链接:

<a href='/auth/facebook'>Sign in with Facebook</a>
<a href='/auth/twitter'>Sign in with Twitter</a>
<a href='/auth/...'>Sign in with ...</a>

我希望浏览器将用户重定向到/auth/...,这样用户就会被重定向到身份验证服务。

有什么办法可以做到吗?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    添加 target="_self" 在 Angular 1.0.1 中有效:

    <a target="_self" href='/auth/facebook'>Sign in with Facebook</a>
    

    此功能已记录在案(https://docs.angularjs.org/guide/$location - 搜索“_self”)

    如果您好奇,请查看角度源代码(第 5365 行 @ v1.0.1)。只有!elm.attr('target') 为真时才会发生点击劫持。

    【讨论】:

    • 适用于 angular 1.2.16 并且可能适用于当前主 github.com/angular/angular.js/blob/master/src/ng/…
    • 必须使用它来启用过渡期,同时将铁路路线转换为角度路线
    • 当我使用 Angular 和 Turbolinks 时,这会导致整个页面重新加载。
    【解决方案2】:

    Fran6co 的替代方法是禁用 $locationProvider 中的 'rewriteLinks' 选项:

    $locationProvider.html5Mode({
        enabled: true,
        rewriteLinks: false
    });
    

    这将完成与调用 $rootElement.off('click') 完全相同的操作,但不会干扰处理应用根元素上的点击事件的其他 javascript。

    docsrelevant source

    【讨论】:

    • 这对我不起作用,但@Fran6co 的solution 几乎可以(见我的评论)。我在加载应用程序的页面上运行它,但没有控制器以锚标记所在的树为目标。
    • 这个答案+1。直到我在 $locationProvider 上启用了 html5Mode,问题才首先出现。
    【解决方案3】:

    这是关闭深度链接的代码。它从 rootElement 禁用 click 事件处理程序。

    angular.module('myApp', [])
       .run(['$location', '$rootElement', function ($location, $rootElement) {
          $rootElement.off('click');
    }]);
    

    【讨论】:

    • 对于 MVC/Angular 混合站点来说,这是一个不错的解决方案,其中一些链接指向一个 mini-SPA,这些链接被 Angular 路由配置拦截,而其他链接则用于常规 MVC 页面请求。在我的情况下,常规链接一直有效,直到加载了 Angular 控制器(使用 SPA 时),此时常规 MVC 链接被劫持并且没有产生响应。如此赞成。
    • 无论您将$location 放入其中,您都需要执行此操作:例如.controller('fooController', function($location) { }) 你需要删除像.controller('fooController', function($element, $location) { $element.off('click'); }) 这样的事件。
    • 谢谢,我在页面上应用过滤器时使用 pushstate 来设置 url。有了这个,我可以使用$location.search() 并且我的&lt;a&gt; 标签仍然可以正常工作。 (无需申请target="_self" everywhere
    • 我用一个混合的 Angular 和 Node/Express 应用程序遇到了这个问题,这就像一个魅力。谢谢!
    • 这最初是有效的,但在进一步测试后,它产生了意想不到的副作用。在混合的 Angular/纯 jQuery 页面上,带有 jQ​​uery e.preventDefault()&lt;a href=#&gt;(在角度控制器之外)曾经可以工作,但现在我遇到了一个与 this 非常相似的错误,听起来很正确 - “$locationWatch 期望 $首先要更新位置服务,然后是浏览器。但是当我直接将状态推送到浏览器[或者在我的情况下导航到#]时,$location 服务仍然具有旧的 url。”我不得不继续寻找替代品。
    【解决方案4】:

    要解决 Nik 的答案,如果您有很多链接并且不想为每个链接添加目标,您可以使用指令:

    Module.directive('a', function () {
        return {
            restrict: 'E',
            link: function(scope, element, attrs) {
                element.attr("target", "_self");
            }
        };
    });
    

    【讨论】:

      【解决方案5】:

      我现在在 Angular 上遇到过几次同样的问题,虽然我提出了两种功能性解决方案,但都感觉像 hack,而且不是很“有棱角”。

      技巧 #1:

      window.location 刷新绑定到链接的click 事件。

      <a 
        href=/external/link.html 
        onclick="window.location = 'http://example.com/external/link.html';"
      >
      

      这种方法的缺点和问题相当明显。

      技巧 #2

      设置执行 $window.location 更改的 Angular $routes。

      // Route
      .when('/external', {
        templateUrl: 'path/to/dummy/template', 
        controller: 'external'
      })
      
      // Controller
      .controller('external', ['$window', function ($window) {
        $window.location = 'http://www.google.com';
      }])
      

      我想您可以使用$routeParams 或查询字符串来扩展它,让一个控制器处理所有“外部”链接。

      正如我所说,这两种解决方案都不是很令人满意,但如果您必须在短期内使其发挥作用,它们可能会有所帮助。

      顺便说一句,我真的很想看到 Angular 支持 rel=external 这种功能,就像 jQueryMobile 使用它来禁用 ajax 页面加载一样。

      【讨论】:

      • 我也希望看到rel=external 也能正常工作。在那之前,我将使用 hack #2。我会尽快将您的答案标记为已接受,但我想再等一会儿,看看是否有人以更 angular-ish 的方式解决了这个问题。谢谢!
      • 我也有类似的想法,特别是在html5mode = true中使用$window.location强制刷新页面——这在Webkit浏览器中无法正常工作;绝对使用target=_self
      【解决方案6】:

      为了补充 Dragonfly 的答案,我发现限制 target="_self" 属性数量的最佳做法是从不将 ng-app 属性放在 body 标记上。通过这样做,您告诉 Angular,body 标签中的 everything 是 Angular 应用程序的一部分。

      如果您在不受 Angular 影响的静态包装器中工作,请将您的 ng-app 属性放在仅围绕您的 Angular 应用程序将要工作的位置的 div(或其他元素)上。这样您只需要将 target='_self' 属性放在将是 ng-app 元素的子元素的链接上。

      <body>
          ... top markup ...
          <div ng-app="myApp">
              <div ng-view></div>
          </div>
          ... bottom markup ...
      </body>
      

      【讨论】:

        【解决方案7】:

        在您的路线中尝试:

        $routeProvider.otherwise({})

        【讨论】:

        • 不起作用。仅当我使用诺亚回答中的外部控制器时。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-24
        相关资源
        最近更新 更多