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

最近遇到 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>


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

示例可以看这儿: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 && inner_html.indexOf("<") == -1) {
	b = doc.createElement("b");
	b.style.display = "none";
	anchor.appendChild(b);
}
anchor.href = href;

if (b) {
	anchor.removeChild(b);
}

7 Replies to “IE下链接包含@字符时的一个问题”

  1. 侵入最小方案: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); }

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s