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>
<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: protocol 和 JavaScript 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);
}
评论:
还真是。。。
修改链接的href属性的时候,在属性值前面加空格可以hacklink.href = ‘ ’+ link.href
果然可以,非常感谢!
<a href="http://www.taobao.com" id="a-test"><span>链接@BABY</span></a>
a 加入span img br 等非文本节点时,此 bug 不会重现
学习了。。。
侵入最小方案: