7个回答

120

在 Angular 1.0.1 中,添加 target="_self" 是可行的:

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

这个功能已经有文档说明 (https://docs.angularjs.org/guide/$location - 搜索 '_self' )

如果你感到好奇,可以查看 Angular 的源代码(@ v1.0.1 的第 5365 行)。只有当 !elm.attr('target') 的值为 true 时,才会发生单击劫持。


适用于Angular 1.2.16,很可能也适用于当前的主版本 https://github.com/angular/angular.js/blob/master/src/ng/location.js#L687 - Patrick Refondini
1
不得不使用此方法来实现在将 Rails 路由转换为 Angular 路由过渡期间的功能。 - Mikey
1
当我在使用Angular和Turbolinks时,这会导致整个页面重新加载。 - a2f0

20

除了Fran6co方法外,另一种方法是在$locationProvider中禁用'rewriteLinks'选项:

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

这将完全实现与调用 $rootElement.off('click') 相同的功能,但不会干扰处理应用程序根元素上的点击事件的其他 JavaScript。

请参阅文档相关源代码


这对我不起作用,但是@Fran6co的解决方案几乎可以(请参见我的评论)。我正在运行它在一个加载应用程序但没有控制器针对锚标记所在的树的页面上。 - mlhDev
1
直到我在$locationProvider上启用了html5Mode,问题才首次出现。 - Ryan Francis

16

以下是关闭深度链接的代码。它禁用了从根元素开始的点击事件处理程序。

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

这是一个很好的解决方案,适用于混合MVC / Angular站点,其中一些链接指向小型SPA,被Angular路由配置拦截,而其他链接则用于普通的MVC页面请求。在我的情况下,常规链接可以正常工作,直到加载了Angular控制器(使用了SPA),此时常规MVC链接被劫持并没有响应。因此,我已经点赞了。 - Sean
无论您在哪里使用$location,您都需要这样做:例如.controller('fooController', function($location) { }),您需要删除事件,如.controller('fooController', function($element, $location) { $element.off('click'); }) - tester
1
谢谢,我正在使用pushstate在页面应用过滤器时设置URL。这样,我就可以使用$location.search()并且仍然可以正常使用我的<a>标签(无需在所有地方应用target="_self")。 - tomvo
1
我在一个混合的Angular和Node/Express应用程序中遇到了这个问题,这个方法非常有效。谢谢! - JFOX
最初这个方法是有效的,但在进一步测试后,它产生了意想不到的副作用。在一个混合使用Angular和纯jQuery的页面上,一个在Angular控制器之外的<a href=#>标签,使用jQuery的e.preventDefault()方法曾经是有效的,但现在我遇到了一个非常类似于这个的错误,听起来很正确 - "$locationWatch期望$location服务首先被更新,然后是浏览器。但当我直接向浏览器推送pushState [或者在我的情况下导航到#]时,$location服务仍然具有旧的URL。" 我必须继续寻找替代方案。 - mlhDev

2

继Nik的回答之后,如果你有很多链接并且不想给每个链接都添加目标,你可以使用一个指令:

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

1

我在使用Angular时遇到了同样的问题,虽然我想出了两种可行的解决方案,但它们都感觉像是一些“hack”而不是真正的Angular。

解决方案1:

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

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

这种方法的缺点和问题非常明显。

技巧 #2

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

// 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”的方式解决了这个问题。谢谢! - Vlad V
我有类似的想法,特别是使用 $window.locationhtml5mode = true 下强制刷新页面——这在 Webkit 浏览器中无法正常工作;一定要使用 target=_self - jlmakes

0

补充Dragonfly的回答,我发现限制target="_self"属性数量的最佳实践是永远不要在body标签上放置ng-app属性。这样做会告诉angular,所有在body标签内的内容都是angular应用程序的一部分。

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

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

0
在你的路由中尝试使用以下代码:

$routeProvider.otherwise({})


不起作用。只有使用Noah答案中的外部控制器才有效。 - Vlad V

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接