如何防止锚标签上的默认值?


342

假设我有一个锚标记,例如

<a href="#" ng-click="do()">Click</a>

如何防止浏览器导航到AngularJS中的#?


14
就像克里斯在下面说的那样,就省去了href
杰西

13
克里斯说,杰西不是href=''用来保持鼠标指针行为的。
oma

1
您只需从href中删除#号,就可以了。
HENG Vongkol 2016年

4
或者只使用href =“ javascript:void(0);” 保留指针但不执行任何操作(直到您添加另一个点击处理程序)
Robba

1
您能否将Chris接受的最佳答案和投票最多的答案更改为stackoverflow.com/a/11672909
Piotr Dobrogost

Answers:


259

更新:此后,我改变了主意。经过更多的开发和花时间进行此工作之后,我相信针对此问题的更好解决方案是执行以下操作:

<a ng-click="myFunction()">Click Here</a>

然后更新您css的规则,以执行以下操作:

a[ng-click]{
    cursor: pointer;
}

它更加简单,并提供完全相同的功能,并且效率更高。希望对将来寻找该解决方案的其他人有所帮助。


以下是我以前的解决方案,仅出于遗留目的而留在这里:

如果您经常遇到此问题,则可以通过以下简单指令来解决此问题:

app.directive('a', function() {
    return {
        restrict: 'E',
        link: function(scope, elem, attrs) {
            if(attrs.ngClick || attrs.href === '' || attrs.href === '#'){
                elem.on('click', function(e){
                    e.preventDefault();
                });
            }
        }
   };
});

它检查所有锚标记(<a></a>),以查看其href属性是否为空字符串("")或哈希('#')或是否有ng-click分配。如果发现这些条件中的任何一个,它将捕获事件并阻止默认行为。

唯一的缺点是它为所有锚标记运行此指令。因此,如果页面上有很多锚标记,而您只想防止其中的少量锚标记的默认行为,则此指令的效率不是很高。但是,我几乎总是想要preventDefault,因此我在AngularJS应用程序中全部使用了此指令。


2
感谢@matejkramny,非常有建设性的批评。有什么建议可以减少它的“混乱”?
网友网球

1
如其他答案所述,具有空白href属性在不同的浏览器中具有不同的行为。尽管我同意这是迄今为止最干净,最有效的解决方案,但确实存在一些跨浏览器的问题。使用指令方法可以使浏览器<a>按正常方式处理标签,但仍可以让OP获得他们正在寻找的答案。
Tennisgent

2
这很奏效,但对于一个非常简单的问题,它的严重矫over过正。Angular使您可以使用$ event访问事件对象,因此您可以完全执行纯js或​​jquery click事件中的操作。看到这个答案stackoverflow.com/a/19240232/1826354和我对此的评论
Charlie Martin

1
是的 您可以。这篇文章还有另外两个答案已经按照您的描述进行了。我同意,这太过分了。这就是为什么我做了我所做的更新。
网游网

6
如果您不关心网站的可访问性,那就很好。取消设置href,就无法使用键盘在该项目上切换。除非添加了tabindex。考虑到所有这些,为什么不只使用preventDefault ...?那就是它的目的。
duhseekoh 2015年

319

根据ngHref文档,您应该可以省略 href或执行href =“”。

<input ng-model="value" /><br />
<a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
<a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
<a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
<a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />

6
这是唯一的实际好答案。任何需要接触DOM或本地事件的问题都值得怀疑
Vincent 2013年

4
这是正确的答案。如果从<a>属性中删除href,AngularJS将调用prevent默认值:
pkozlowski.opensource,2013年

25
放弃href属性的唯一缺点是,将鼠标悬停在链接上时会丢失普通的“指针”光标。您可以通过在样式表中添加一条规则来解决此问题:a:hover {cursor:pointer; }
karlgold 2013年

35
请记住,这也会使标签不可贴标签,这对访问性不是很友好。
理查德·萨雷

3
对我来说,浏览器仍然会冒着点击动作:/
Matej 2015年

238

您可以将$ event对象传递给您的方法,然后对其进行调用$event.preventDefault(),这样就不会发生默认处理:

<a href="#" ng-click="do($event)">Click</a>

// then in your controller.do($event) method
$event.preventDefault()

13
是的,您还可以调用$ event.stopPropagation()以使事件不会冒泡(基本上,您可以访问W3C定义的Event对象:w3.org/TR/DOM-Level-2- Events / events.html#Events-Event
mna

1
请注意,在当时这被写了,留下的href空的(或不存在)做工作在IE8 / 9和Opera。这是一年前的事,但我还没有机会再试一次(当时我在Github上打开了一个问题,但我认为他们是在一段时间前重新设置了问题)。如果这是固定的(或者您不关心这些浏览器),则一定要使用Chris的答案!如果有人可以尝试并评论/编辑答案,那就更好了。
mna 2013年

1
@PuerkitoBio-我可以确认IE8及以下版本仍需要$event.preventDefault()... IE税。
Scotty.NET

4
将$ event传递给控制器​​意味着在控制器中引用DOM,这意味着您已将视图和控制器耦合在一起。您可以在评估表达式中直接调用$ event方法:ng-click="do(); $event.preventDefault()例如,...,但这不是必需的,因为下面@Chris的答案是正确的。但是,这在嵌套ngClicks并希望致电的情况下可能对人们有所帮助$event.stopPropagation()
Ben Lesh

2
最后是SEO友好的解决方案。您可能还想在不重新加载ng-view的情况下更新浏览器URL-joelsaupe.com/programming/… 这样,您的链接不会重新加载视图,但可以在新标签页中打开,搜索引擎可以关注它们。好极了!
2014年

111

我更喜欢对此类事情使用指令。这是一个例子

<a href="#" ng-click="do()" eat-click>Click Me</a>

和指令代码为eat-click

module.directive('eatClick', function() {
    return function(scope, element, attrs) {
        $(element).click(function(event) {
            event.preventDefault();
        });
    }
})

现在,您可以将eat-click属性添加到任何元素,它将preventDefault()自动进行编辑。

优点:

  1. 您不必将丑陋的$event对象传递给do()函数。
  2. 您的控制器更易于单元测试,因为它不需要存根$event对象

1
@Kato Angular带有自己的jQuery子集,使我们的生活变得轻松。
尼尔

3
额外的好处 - 如果您认为这很重要,那么它也适用于IE8及以下版本。
Scotty.NET 2013年

1
我越来越Error: $ is not defined。我想念什么?
Bilal Mirza

7
我试过了angular.element(element).bind('click', function(event){...});。有效。参考:jQLite
Bilal Mirza

3
如果您问我类似这样的简单指令,似乎有点肿...检查克里斯他的回答如下
Wilt

54

尽管Renaud提供了很好的解决方案

<a href="#" ng-click="do(); $event.preventDefault()">Click</a> 

我个人发现在某些情况下,您还需要$ event.stopPropagation()以避免某些副作用

<a href="#" ng-click="do(); $event.preventDefault(); $event.stopPropagation();">
    Click</a>

将是我的解决方案


34
ng-click="$event.preventDefault()"

13
这是最好的解决方案。当然,您也可以将$ event对象传递给您的作用域函数。就像ng-click =“ myFunction($ event,otherParams)然后是myFunction中的$ event.preventDefault()一样。为此滚动自己的指令是过分的
查理·马丁

34

我找到的最简单的解决方案是:

<a href="#" ng-click="do(); $event.preventDefault()">Click</a>

这不仅最简单,而且不会像其他解决方案中所建议的那样将事件与控制器耦合。应该不惜一切代价避免将事件耦合到控制器,因为这会使测试变得更加困难。
jornare 2014年

11

因此,通读这些答案,我想@Chris仍然是最“正确”的答案,但是它有一个问题,它没有显示“指针”...。

因此,这里有两种无需添加游标即可解决此问题的方法:指针样式:

  1. 使用javascript:void(0)代替#

    <a href="javascript:void(0)" ng-click="doSomething()">Do Something</a>
  2. $event.preventDefault()ng-click指令中使用(这样就不会用与DOM相关的引用来破坏控制器):

    <a href="#dontGoHere" ng-click="doSomething(); $event.preventDefault()">Do Something</a>

我个人更喜欢前者。javascript:void(0)还有其他好处在这里讨论。在该链接中还讨论了“不打扰的JavaScript”,这是令人恐惧的最新消息,不一定直接应用于有角度的应用程序。


2
为什么这被否决?我还注意到指针未与克里斯的答案一起显示。
Wim Deblauwe 2014年

2
javascript:void(0)比#更好,如果您配置错误,它可以在路由上起作用。+1
Shay Elkayam 2014年

2
我正要为此写一个答案。您也可以这样做javascript:;
Adrian

10

你可以做如下

1. href从anchor(a)标签中删除属性

2.将css中的指针光标设置为ng click元素

 [ng-click],
 [data-ng-click],
 [x-ng-click] {
     cursor: pointer;
 }

9

的HTML

这里是纯angularjs:在ng-click函数附近,您可以通过分隔分号来编写preventDefault()函数

<a href="#" ng-click="do(); $event.preventDefault(); $event.stopPropagation();">Click me</a>

JS

$scope.do = function() {
    alert("do here anything..");
}

(要么)

您可以通过这种方式进行操作,这已经在这里讨论过。

的HTML

<a href="#" ng-click="do()">Click me</a>

JS

$scope.do = function(event) {
    event.preventDefault();
    event.stopPropagation()
}

7

试试这个选项,我上面还没有列出:

<a href="" ng-click="do()">Click</a>

6

既然您正在制作一个Web应用程序,为什么需要链接?

交换锚点到按钮!

<button ng-click="do()"></button>

2
既然wen不能在webapp中使用锚?
罗宾·范·巴伦

1
我指的是大多数Web应用程序都不需要像网站那样的相对链接,它们通常也只是将锚链接用作javascript触发器,而不链接到页面。因此,具有默认样式重置的按钮在语义上同样正确(如果不是更多的话)。
sidonaldson

3
@sidonaldson实际上,当今很多Web应用程序都严重依赖链接。看一下angularjs路由。
罗伯特

1
@Robert是的,但是如果您使用内置路由,则无需管理“阻止默认值”,它已为您完成。我想因为发布者想要取消锚链接,所以他正在谈论非路线链接。例如,启动模态等
sidonaldson

2
这个答案应该有更多的支持。在许多情况下,如果要防止默认的锚定行为,则可以将锚定用作按钮而不是链接。
ItsCosmo 2015年

6

如果仍然相关:

<a ng-click="unselect($event)" />

...

scope.unselect = function( event ) {
 event.preventDefault();
 event.stopPropagation();
}

...


5

我会去:

<a ng-click="do()">Click</a>
  • 因为根据文档,您应该可以离开href,然后Angular将为您处理prevent default!

整个这个防止默认的事情一直困扰着我,因此我在这里创建了一个JSFiddle来 说明Angular在何时何地防止默认

JSFiddle使用的是Angular的指令-因此它应该完全相同。您可以在此处查看源代码:标签源代码

我希望这将有助于一些澄清。

我本想将文档发布到ngHref,但由于我的声誉而不能。


5

这就是我一直在做的。奇迹般有效!

<a href ng-click="do()">Click</a>

4

或者,如果您需要内联,则可以执行以下操作:

<a href="#" ng-click="show = !show; $event.preventDefault()">Click to show</a>

4

很多答案似乎是过分的。对我来说,这有效

 <a ng-href="#" ng-click="$event.preventDefault();vm.questionContainer($index)">{{question.Verbiage}}</a>

2

我需要存在href属性值以进行降级(当js关闭时),因此我不能使用空的href属性(或“#”),但是上面的代码对我不起作用,因为我需要一个事件( e)变量。我创建了自己的指令:

angular.module('MyApp').directive('clickPrevent', function() {
  return function(scope, element, attrs) {
    return element.on('click', function(e) {
      return e.preventDefault();
    });
  };
});

在HTML中:

<a data-click-prevent="true" href="/users/sign_up" ng-click="openSignUpModal()">Sign up</a>

2

从网球场的答案中借来的。我喜欢您不必创建自定义指令来添加所有链接。但是,我无法让他在IE8中工作。这是最终对我有用的东西(使用角度1.0.6)。

注意,“ bind”允许您使用angular提供的jqLit​​e,因此无需使用完整的jQuery进行包装。还需要stopPropogation方法。

.directive('a', [
    function() {
        return {
            restrict: 'E',
            link: function(scope, elem, attrs) {

                elem.bind('click', function(e){
                    if (attrs.ngClick || attrs.href === '' || attrs.href == '#'){
                        e.preventDefault();
                        e.stopPropagation();
                    }
                })
            }
        };
    }
])

3
这杀死了很多人。例如,当我使用Twitter Bootstrap时dropdown,我希望传播而不是默认行为。建议使用此代码段。
罗宾·范·巴伦

2

使用锚点进行角度引导时,我遇到了同样的问题。我发现唯一避免使用有害副作用(即,由于使用preventDefault()而导致下拉列表未关闭)的解决方案是使用以下方法:

 <a href="javascript:;" ng-click="do()">Click</a>

2

如果您永远不想访问href ...,则应更改标记并使用按钮而不是锚标记,因为从语义上讲它不是锚或链接。相反,如果您有一个进行一些检查然后重定向的按钮,则应该是一个链接/锚标记,而不是一个按钮...出于SEO的目的以及测试[在此处插入测试套件]。

对于只希望有条件重定向的链接,例如提示保存更改或确认脏状态...,应使用ng-click =“ someFunction($ event)”并在validateError的someFunction中的preventDefault和StopPropagation上使用。

仅仅因为你能做并不意味着你应该。javascript:void(0)在一天中运作良好...但是由于骇客/骇客浏览器在href内标记了使用javascript的应用/网站,因此没有理由在上面使用ducktype。

从2010年开始,应该是2016年。如果您仍然必须支持IE8,则您应该重新评估您的营业地点。自2010年以来,我们就无处使用按钮之类的链接了。


1
/* NG CLICK PREVENT DEFAULT */

app.directive('ngClick', function () {
    return {
        link: function (scope, element, attributes) {
            element.click(function (event) {
                event.preventDefault();
                event.stopPropagation();
            });
        }
    };
});

1

您应该做的是href完全忽略属性。

如果你看一下源代码a元素指令(这是方芯的一部分),它规定在第29行- 31:

if (!element.attr(href)) {
    event.preventDefault();
}

这意味着Angular已经解决了没有href的链接问题。您唯一遇到的问题就是CSS问题。您仍然可以将指针样式应​​用于具有ng-clicks的锚点,例如:

a[ng-click] {
    /* Styles for anchors without href but WITH ng-click */
    cursor: pointer;
}

因此,您甚至可以通过标记实际的链接,使它们具有更细微的样式,然后再执行功能,从而使您的网站更易于访问。

编码愉快!


1

您可以在$ location的Html5Mode中禁用url重定向以实现目标。您可以在用于页面的特定控制器中定义它。像这样:

app.config(['$locationProvider', function ($locationProvider) {
    $locationProvider.html5Mode({
        enabled: true,
        rewriteLinks: false,
        requireBase: false
    });
}]);


1

如果您使用的是Angular 8或更高版本,则可以创建一个指令:

import { Directive, HostListener } from '@angular/core';

@Directive({
  selector: '[preventDefault]'
})
export class PreventDefaultDirective {

  @HostListener("click", ["$event"])
  public onClick(event: any): void
  {
    console.log('click');
    debugger;
      event.preventDefault();
  }

}

在组件的锚标签上,您可以像这样进行连接:

  <a ngbDropdownToggle preventDefault class="nav-link dropdown-toggle" href="#" aria-expanded="false" aria-haspopup="true" id="nav-dropdown-2">Pages</a>

应用模块应具有以下声明:

import { PreventDefaultDirective } from './shared/directives/preventdefault.directive';


@NgModule({
  declarations: [
    AppComponent,
    PreventDefaultDirective

-1

一种替代方法可能是:

<span ng-click="do()">Click</span>

1
滥用a span进行点击是一种可怕的做法。只是去@tennisgent的答案-锚没有href定义。
罗宾·范·巴伦


1
如果您点击<span> Hello </ span>,是什么时候可以点击?规范可能说的是,可以在诸如<a>或<button>之类的可点击元素内使用<span>。但话又说回来,可以使所有内联块元素(img,span等)都可单击。跨度本身不可单击。
罗宾·范·巴伦

1
@RobinvanBaalen请参阅上面的链接。至少从HTML 4.01开始就定义了span元素的onclick属性。
Terence Bandoian 2015年

1
我从未说过添加事件处理程序在一定范围内是行不通的。我说过不好的做法是使用JavaScript事件处理程序来使诸如span,div,section,ul,li等不可点击元素可点击。这都是关于语义的。HTML中的语义是一种通过使用适当的元素在页面上赋予内容含义和结构的实践。
罗宾·范·巴伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.