JavaScript通过href属性获取元素?

66

我有下面的脚本

var els = document.getElementsByTagName("a");
for(var i = 0, l = els.length; i < l; i++) {
  var el = els[i];
  el.innerHTML = el.innerHTML.replace(/link1/gi, 'dead link');
}

然而,这个搜索是通过页面进行的,由于有许多链接,需要大约20秒的时间才能完成。

但是我只需要针对具有特定 href元素进行操作,例如:http://domain.example/

因此,理想情况下,我希望能够以类似于jQuery的方式进行操作,但不使用框架。因此,类似于以下代码:

var els = document.getElementsByTagName("a[href='http://domain.example']");

我应该如何处理,以便它只搜索具有与之匹配的 href 的对象?


2
你想要支持哪些浏览器?你可以尝试使用 document.querySelectorAll 来查看是否有所不同,但是这种方法在 IE7 及更早版本中不可用。另一个可能的选择是使用 CSS3 来改变外观和/或添加一些额外的文本。 - Felix Kling
@FelixKling,querySelectorAll会产生如此大的差异吗?除非没有显示所有代码,否则似乎OP的代码已经相当简洁了 :) - Ja͢ck
我会写一个函数来处理所有链接的onclick事件。这样,一旦有人点击链接,您就可以进行更改。 - Robert Levy
@Jack:我不知道querySelectorAll的内部工作原理。但这就是为什么OP应该尝试和测试它的原因。 - Felix Kling
1
@Jack,这段代码很简洁,但是它使用了一个计算成本很高的属性。 - Alnitak
我觉得我现在要尝试以不同的方式来做这个了,哈哈,因为我注意到它必须运行大约420个A和1020个div,所以速度非常慢!也许在它到达用户之前我会用php来完成它!谢谢。 - owenmelbz
2个回答

137

2016年更新

自从这个问题发布以来已经过去了4年多,事情有了很大的进展。

不能使用:

var els = document.getElementsByTagName("a[href='http://domain.example']");

但你可以使用的是:

var els = document.querySelectorAll("a[href='http://domain.example']");

(注意:请查看下面的浏览器支持情况)

这将使您问题中的代码完全按照您的期望工作:

for (var i = 0, l = els.length; i < l; i++) {
  var el = els[i];
  el.innerHTML = el.innerHTML.replace(/link1/gi, 'dead link');
}

如果你想要获取所有以'http://domain.example'开头的链接,甚至可以使用像a[href^='http://domain.example']这样的选择器:

var els = document.querySelectorAll("a[href^='http://domain.example']");

for (var i = 0, l = els.length; i < l; i++) {
  var el = els[i];
  el.innerHTML = el.innerHTML.replace(/link/gi, 'dead link');
}

请参见:演示

浏览器支持

根据Can I use截至2016年6月的数据,浏览器支持情况相当不错:

caniuse.com/queryselector (有关最新信息,请参见http://caniuse.com/queryselector

IE6IE7不支持,但IE6已经过时了 而IE7很快也会随着其0.68%的市场份额而过时。

IE8已经超过7年的历史,它部分地支持querySelectorAll - 我所指的“部分地”是指您可以使用CSS 2.1选择器,如[attr][attr="val"][attr~="val"][attr|="bar"]和一小部分CSS 3选择器幸运的是,它们包括: [attr^=val][attr$=val][attr*=val],因此看起来IE8对我上面的示例没有问题。

IE9IE10IE11 都可以毫无问题地支持 querySelectorAll,同样的,ChromeFirefoxSafariOpera所有主要的桌面和移动浏览器也是如此。

换句话说,我们可以放心地在生产中开始使用 querySelectorAll

更多信息

欲了解更多信息,请参见:

请参考此答案,了解querySelectorAllquerySelectorqueryAllquery之间的区别,以及它们何时从DOM规范中删除。

@OwenMelbourne 这可能是选择链接更高效的方法,但是像那样使用 .innerHTML.replace 仍然是替换内容的错误方式。 - Alnitak
@Alnitak,如果不使用replace,您会如何使用substring和splice来替换“link”一词为“dead link”? - rsp
据我所知,原问题中的正则表达式/link1/只是一个占位符,而不是OP期望被替换的字面内容。 - Alnitak
1
@Alnitak 我知道这只是一个占位符,但如果它是任何其他正则表达式,会有什么区别吗?我的目标基本上是要显示仅将 getElementsByTagName 更改为 querySelectorAll 就可以使其余代码按预期工作而无需更改。请参见我的演示 - rsp

24

读写每个元素的 innerHTML 属性可能相当昂贵,从而导致您的速度变慢 - 它强制浏览器对该元素进行“序列化”,然后您通过正则表达式运行它,然后再次“反序列化”。更糟糕的是,您正在为 每个 a 元素执行此操作,即使它不匹配。

相反地,请尝试直接查看 a 元素的属性:

var els = document.getElementsByTagName("a");
for (var i = 0, l = els.length; i < l; i++) {
    var el = els[i];
    if (el.href === 'http://www.example.com/') {
        el.innerHTML = "dead link";
        el.href = "#";
    }
}

在现代浏览器上,W3C的兼容性更好了,你可以使用 document.querySelectorAll() 更高效地获取你想要的链接:

var els = document.querySelectorAll('a[href^=http://www.example.com/]');
for (var i = 0, l = els.length; i < l; i++) {
    els[i].textContent = 'dead link';
    els[i].href = '#';
}

如果您希望匹配多个域名,或者同时匹配 http:https: ,那么这种方法就不够灵活。


当我使用“.textContent || .innerText”结构时,我可以获得更好的性能;http://blogger.ziesemer.com/2007/10/innerhtml-and-innertext-slow.html - Ja͢ck
肯定比之前快,但大约循环了1500次后就变慢了! - owenmelbz
+1 对于优化的 for 循环只在开头检查长度一次,我从未想过直接将其放入循环中! - Georges Oates Larsen
el.href === 'http://www.example.com/myfile.html' 在主流浏览器的 Mac OS 环境下可以运行,但在 Ubuntu 或 Windows 环境下无法工作,原因不详。我通过使用 el.href.indexOf("myfile.html") 来解决了这个问题。谢谢。 - HelpNeeder
为什么要两次缓存els.length的值?首先使用els_length = els.length (我理解),然后使用l = els_length (我不理解)。访问els_length和访问l速度不是一样快吗? - Peter
1
@Sorry-Im-a-N00b,是的,你真的是一个n00b。正如已经写过的那样,els.length的评估只会在一次迭代中完成,而不是每次迭代都进行。你的编辑是错误的,批准你的编辑的人也应该更好地了解这一点。 - Alnitak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接