IE下链接包含@字符时的一个问题

2011-11-30

最近遇到 IE 下的一个闻所未闻的 bug:如果 <a> 元素的子节点为纯文本节点(即 nodeType 为 3,innerHTML 中没有 HTML 标签),并且值包含“@”字符,则在修改该 <a> 元素的 href 属性时,它的 innerHTML 也会跟着变。

重现 bug 的代码类似这样:

<meta charset="utf-8" />
请用 IE6/7/8 访问本页面

<a id="a-test" href="http://www.taobao.com">链接@BABY</a>

<script>
	setTimeout(function () {
		var a = document.getElementById("a-test");
		a.href = "http://rate.taobao.com/";
//		a.setAttribute("href", "http://rate.taobao.com/");
	}, 3000);
</script>

示例可以看这儿:bug 示例。请用 IE6、IE7 或 IE8 打开,IE9 中已没有这个问题,同时,在 IE9 的兼容模式下也正常。可以看到,页面打开时,链接的内容为“链接@BABY”,一切正常,但当 js 函数执行,修改了 <a> 元素的 href 属性时,它的 innerHTML 值也变成了同样的值。除了直接给 a.href 赋值外,使用 a.setAttribute 方法也不行,甚至加上 a.setAttribute第三个参数也不行。

这个问题看起来是 IE6/7/8 的 bug。搜索了很久,与几位同事也一起研究了好久,但都没有找到有关这个问题的描述及解决办法。

最后,只好使出了最暴力但是有效的方法:

var a = document.getElementById("a-test"), s;
s = a.innerHTML; // 先记下 innerHTML
a.href = "http://rate.taobao.com/";
a.innerHTML = s; // 再将 innerHTML 的值写回去

不知道有没有更好的解决办法。



补充(2011-12-01)

上面那种先记下 innerHTML 的值,修改 href 之后再将它写回去的做法是有隐患的。比如,<a> 元素里面可能不是一段文本,而是一个 <img>,并且这个 <img> 上绑定了事件,那么,再将 innerHTML 写回去时,就会生成新的节点,原来绑定的事件也就失效了。

感谢 sophiasmth 提供了一个更好的方法,只需在要写入的 href 的值前面加一个半角空格即可,而现代浏览器会安全地忽略掉 href 值前后的多余的空白字符。即:

a.href = " " + "http://rate.taobao.com/";

// 或者:

a.href = " http://rate.taobao.com/"; // 注意前面的空格

暂时还没发现这种方式的副作用。



补充 2(2011-12-01)

进一步测试,发现如果 <a> 链接的内容以“www.”开头(如),也会有这个问题(测试页面)。看起来,凡是形如电子邮件(包含“@”字符)或网址(以“www.”开头)的字符串,在 IE6/7/8 中都有特殊行为。



补充 3(2011-12-05)

经小马的帮助,发现国外也有类似的报告,如 JavaScript modifying href changes link text as well for mailto: protocolJavaScript HREF bug in IE



补充 4(2013-03-25)

href 前面加一个空格的方式副作用太多,最后决定使用先加一个 <b></b> 节点然后再删除的方法。

var b,
	inner_html = anchor.innerHTML;

if (inner_html &amp;&amp; inner_html.indexOf("<") == -1) {
	b = doc.createElement("b");
	b.style.display = "none";
	anchor.appendChild(b);
}
anchor.href = href;

if (b) {
	anchor.removeChild(b);
}
分类: 编程 标签: JavaScript
前一篇: 学习GTD
后一篇: 生产率法则

相关文章:

评论:

sophiasmth
在 2011-12-01 14:58 写道:

还真是。。。

回复
sophiasmth
在 2011-12-01 15:06 写道:

修改链接的href属性的时候,在属性值前面加空格可以hacklink.href = ‘ ’+ link.href

回复
oldj
在 2011-12-01 15:06 写道:

果然可以,非常感谢!

回复
vesper
在 2011-12-01 17:42 写道:

<a href="http://www.taobao.com" id="a-test"><span>链接@BABY</span></a>

回复
aben
在 2011-12-01 17:49 写道:

a 加入span img br 等非文本节点时,此 bug 不会重现

回复
squall
在 2011-12-05 14:02 写道:

学习了。。。

回复
yiminghe
在 2012-08-08 14:01 写道:

侵入最小方案:

var t = document.getElementById("t"),
  span;
if (t.childNodes.length == 1 && t.childNodes[0].nodeType == 3) {
  span = document.createElement("span");
  span.style.display = "none";
  t.appendChild(span);
}
document.getElementById("t").href = 'http://www.taobao.com';
if (span) {
  t.removeChild(span);
}
回复

发表评论:

电子邮件地址不会被公开。 必填项已用 * 标注。