a 标签的 href 属性和 onclick 事件

a 标签上有属性 href,标明了点击元素跳转的另一个 url。偶尔总需要在跳转前后做些什么,所以顺理成章的在 a 标签上绑定了 onclick 事件。href 属性跳转和 click 事件之间究竟是什么关系呢?

href 与 onclick 的执行顺序

如果 a 标签上出现了 href 属性并同时绑定了 click 事件(当然并不推荐这样做),是怎样一个执行顺序呢?

随手写了一个栗子:

1
<a href="nameList.html">btn</a>
1
2
3
4
5
<script>
$("a").click(function(){
alert('a');
})
</script>

点击按钮,在页面跳转之前跳出提示框,关掉提示框后跳转到 nameList.html 页面。显而易见,click 事件是在页面开始跳转之前执行的。

禁用 href 属性

href 属性的作用只是实现页面跳转,而 onclick 事件的作用则强大很多。那么索性就把 href 跳转禁用掉,直接执行 onclick 里的代码。

最开始总会想到最简单粗暴的办法,把 href 的路径置为空,或者 href="#",就像这样:

1
<a href="">btn</a>
1
2
3
$("a").click(function(){
alert('a');
})

关闭提示框以后页面果然不再跳转了,但是,你看见页面闪动了一下吗?事实上,空字符串和 # 包含了一个位置信息,默认的锚是 #top,也就是网页的头部。在页面很长的时候会使用 # 来定位页面的具体位置,格式为:# + id。

如果你的页面足够长,就会发现当你关闭提示框后页面回到了顶部。举个简单粗暴的例子,在 <a> 前加入了 100 项无序列表,使长度超过视窗的高度,按钮在列表底部。

1
2
3
4
5
6
7
<ul>
<li>1</li>
<li>2</li>
...
<li>100</li>
</ul>
<a href="">btn</a>
1
2
3
$("a").click(function(){
alert('a');
})

无论是 <a href=""></a> 还是 <a href="#"></a> 的写法,点击按钮时,页面虽然不会跳转,但会重定位到页面顶部。

当然,如果 a 标签完全去掉 href 属性是完全可行的,既不会跳转,也不会重定向到头部,但是如果这样,为什么不用 span 标签来代替它呢?

而真正实现禁用 href 属性的写法有多种。

方法一:javascript:void(0)

将代码改成如下。点按钮,跳提示框,关闭,无跳转无重定位,完美实现了禁用 href 属性。

1
<a href="javascript:void(0)">btn</a>
1
2
3
$("a").click(function(){
alert('a');
})

这段代码最精华的部分就是这句 javascript:void(0),表示一个死链接。

1
javascript:void (expression)

其中,javascript 为协议名称,expression 为 javascript 表达式,返回类型为 void ,即无返回值。所以,如果你这样写:

1
<a href="javascript:void (document.form.submit())"></a>

那么点击将会提交表单。

javascript:void(0) 协议中,当用户链接时,void(0) 计算为 0,Javascript 上没有任何效果。不过重要的是,javascript: void(0) 毕竟是个伪协议,少写的好。而且存在浏览器兼容 bug(有待考证),因此这种写法并不做推荐。

方法二:preventDefault() 方法

1
<a href="#">btn</a>
1
2
3
4
$("a").click(function(e){
e.preventDefault();
alert('a');
})

通过取消事件的默认动作防止跳转。

方法三:return false

1
<a href="#">btn</a>
1
2
3
4
$("a").click(function(){
alert('a');
return false;
})

当执行上述代码时,你会发现它像上面的方法一样,有效地阻止了 a 标签的默认行为。事实上,当我们每次调用 return false 时,都会执行以下三个步骤:

  • event.preventDefault();
  • event.stopPropagation();
  • 停止回调函数执行并立即返回。

举个很简单的例子:

1
2
3
<div class="parent">
<a herf="#">btn</a>
</div>
1
2
3
4
5
6
7
8
9
<script>
$(".parent").click(function(e){
alert('b');
})
$("a").click(function(e){
e.preventDefault();
alert('a');
})
</script>

因为事件冒泡,当我们点击 btn 按钮时,会先跳出显示 “a” 的提示框,再跳出显示 “b” 的提示框。但是页面不会跳转,因为有 e.preventDefault()

如果我们将 a 的点击事件改成如下处理方式:

1
2
3
4
$("a").click(function(e){
alert('a');
return false;
})

那么将不再跳出显示内容为 “b” 的提示框,因为在 return false 语句中,执行了 event.stopPropagation() 方法。