58

我将运行 document.querySelectorAll() 很多,并且想要一个简写别名。

var queryAll = document.querySelectorAll

queryAll('body')
TypeError: Illegal invocation

不工作。然而:

document.querySelectorAll('body')

仍然如此。如何使别名起作用?

4

10 回答 10

101

这似乎有效:

const queryAll = document.querySelectorAll.bind(document);

bind返回一个与函数相同的新函数querySelectorAll,其中方法this内部的值querySelectorAll绑定到document对象。

绑定功能仅在 IE9+(和所有其他浏览器)中受支持 - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind


更新:事实上,您可以创建一系列文档方法的快捷方式,如下所示:

const query = document.querySelector.bind(document);
const queryAll = document.querySelectorAll.bind(document);
const fromId = document.getElementById.bind(document);
const fromClass = document.getElementsByClassName.bind(document);
const fromTag = document.getElementsByTagName.bind(document);
于 2013-02-19T00:33:03.457 回答
26

一个常见的答案是使用$and$$和。这个别名模仿了 jQuery 的别名。querySelectorquerySelectorAll

例子:

const $ = document.querySelector.bind(document)
const $$ = document.querySelectorAll.bind(document)

$('div').style.color = 'blue'
$$('div').forEach(div => div.style.background = 'orange')
div {
  margin: 2px;
}
<div>
  test
</div>
<section>
  <div>
    hello
  </div>
  <div>
    foo
  </div>
</section>

于 2017-09-06T15:29:14.827 回答
15

JavaScript 解释器抛出错误,因为querySelectorAll()应该在文档上下文中调用。

当您尝试调用console.log()别名时会引发相同的错误。

所以你需要像这样包装它:

 function x(selector) {
     return document.querySelectorAll(selector);
 }
于 2012-11-14T17:29:46.247 回答
10

我的解决方案涵盖以下四个用例:

  • document.querySelector(...)
  • document.querySelectorAll(...)
  • element.querySelector(...)
  • element.querySelectorAll(...)

编码:

let doc=document,
    qsa=(s,o=doc)=>o.querySelectorAll(s),
    qs=(s,o=doc)=>o.querySelector(s);

在参数方面,选择器s是必需的,但容器元素对象o是可选的。

用法:

  • qs("div"): 查询整个文档的第一个 div,返回那个元素
  • qsa("div"):查询整个文档的所有 div,返回所有这些元素的 nodeList
  • qs("div", myContainer): 在 myContainer 元素中查询第一个 div,返回该元素
  • qsa("div", myContainer):在 myContainer 元素中查询所有 div,返回所有这些元素的 nodeList

为了使代码略短(但效率不高),qs代码可以编写如下:

let qs=(s,o=doc)=>qsa(s,o)[0];

上面的代码使用了 ES6 特性(let、箭头函数和默认参数值)。一个 ES5 等价物是:

var doc=document,
    qsa=function(s,o){return(o||doc).querySelectorAll(s);},
    qs=function(s,o){return(o||doc).querySelector(s);};

或等效的较短但效率较低的 ES5 版本qs

var qs=function(s,o){return qsa(s,o)[0];};

下面是一个工作演示。为了确保它适用于所有浏览器,它使用 ES5 版本,但如果你要使用这个想法,请记住 ES6 版本更短:

var doc = document;

var qs=function(s,o){return(o||doc).querySelector(s);},
    qsa=function(s,o){return(o||doc).querySelectorAll(s);}

var show=function(s){doc.body.appendChild(doc.createElement("p")).innerHTML=s;}

//           ____demo____       _____long equivalent______      __check return___      _expect__ 
//          |            |     |                          |    |                 |    |         |

let one   = qs("div");      /* doc.querySelector   ("#one") */ show(one  .id    ); // "one"
let oneN  = qs("div",one);  /* one.querySelector   ("div")  */ show(oneN .id    ); // "oneNested"
let many  = qsa("div");     /* doc.querySelectorAll("div")  */ show(many .length); // 3
let manyN = qsa("div",one); /* one.querySelectorAll("div")  */ show(manyN.length); // 2
<h3>Expecting "one", "oneNested", 3 and 2...</h3>
<div id="one">
  <div id="oneNested"></div>
  <div></div>
</div>

于 2016-02-29T08:40:57.437 回答
7

这会起作用,您需要使用call()apply()使用适当的上下文来调用别名。

func.call(context, arg1, arg2, ...) 
func.apply(context, [args]) 

var x = document.querySelectorAll;
x.call(document, 'body');
x.apply(document, ['body']);
于 2012-11-14T17:28:18.953 回答
6

我采用了@David Muller 的方法,并使用 lambda 对其进行了单线化

let $ = (selector) => document.querySelector(selector);
let $all = (selector) => document.querySelectorAll(selector);

例子:

$('body');
// <body>...</body>
于 2018-05-09T06:58:26.877 回答
4
function x(expr)
{
    return document.querySelectorAll(expr);
}
于 2012-11-14T17:23:42.117 回答
2

这是我的看法。如果选择器有多个匹配项,则返回 like querySelectorAll。如果只找到一个匹配项,则返回类似querySelector.

function $(selector) {
  let all = document.querySelectorAll(selector);
  if(all.length == 1) return all[0];
  return all;
}

let one = $('#my-single-element');
let many = $('#multiple-elements li');

2019 年更新

今天我对这个问题有了新的看法。在这个版本中,您还可以使用这样的基础:

let base = document.querySelectorAll('ul');

$$('li'); // All li
$$('li', base); // All li within ul

功能

function $(selector, base = null) {
  base = (base === null) ? document : base;
  return base.querySelector(selector);
}

function $$(selector, base = null) {
  base = (base === null) ? document : base;
  return base.querySelectorAll(selector);
}
于 2018-12-16T17:59:43.487 回答
1

如果您不关心支持没有人应该再使用的古老、糟糕的浏览器,那么您可以这样做:

const $ = (sel, parent = document) => parent.querySelector(sel);
const $$ = (sel, parent = document) => Array.from(parent.querySelectorAll(sel));

以下是一些使用示例:

// find specific element by id
console.log($("#someid"));
// find every element by class, within other element
// NOTE: This is a contrived example to demonstrate the parent search feature.
// If you don't already have the parent in a JavaScript variable, you should
// query via $$("#someparent .someclass") for better performance instead.
console.log($$(".someclass", $("#someparent")));
// find every h1 element
console.log($$("h1"));
// find every h1 element, within other element
console.log($$("h1", $("#exampleparent")));
// alternative way of finding every h1 element within other element
console.log($$("#exampleparent h1"));
// example of finding an element and then checking if it contains another element
console.log($("#exampleparent").contains($("#otherelement")));
// example of finding a bunch of elements and then further filtering them by criteria
// that aren't supported by pure CSS, such as their text content
// NOTE: There WAS a ":contains(text)" selector in CSS3 but it was deprecated from the
// spec because it violated the separation between stylesheets and text content, and you
// can't rely on that CSS selector, which is why you should never use it and should
// instead re-implement it yourself like we do in this example.
// ALSO NOTE: This is just a demonstration of .filter(). I don't recommend using
// "textContent" as a filter. If you need to find specific elements, use their way
// more reliable id/class to find them instead of some arbitrary text content search.
console.log($$("#exampleparent h1").filter(el => el.textContent === "Hello World!"));

我提供的函数使用了大量的现代 JS 特性:

  • const确保函数变量不能被覆盖。
  • 定义为箭头函数又名 lambda 的函数:(args) => code with implied return statement
  • 默认参数(2016年之前的浏览器不支持)
  • no {}or return,因为如果函数体中只有 1 条语句,则可以跳过这些语句。
  • 使用了现代函数Array.from(),它将querySelectorAll结果(始终是NodeList或空 NodeList)转换为Array,这基本上是每个开发人员都想要的。因为这就是您访问.filter()其他 Array 函数的方式,这些函数允许您使用干净、简短的代码进一步处理发现的节点。并Array.from()创建所有元素的浅表副本,这意味着它的速度非常快(它只是将内存引用/指针复制到原始 NodeList 中的每个Node DOM 元素)。它是一个主要的 API 增强器。

如果你关心古老的浏览器,你仍然可以使用我的功能,但在你发布网站时使用Babel将现代 JS 转换为旧的 ES5。

我的建议是用 ES6 或更高版本编写您的整个网站,然后如果您关心来自 Windows XP 和其他死操作系统的访问者,或者只是 5 年以上未更新浏览器的随机人,则使用 Babel。

但我不建议使用 Babel。不要再担心那些使用旧浏览器的人了。这是他们的问题,不是你的。

现代“应用程​​序”世界非常深刻地基于 Web 浏览器、JavaScript 和现代 CSS,而如今,您的大多数访问者都拥有现代的、自动更新的浏览器。没有现代浏览器,你基本上无法过现代生活,因为现在有很多网站需要它。

在我看来,从 1993 年开始,期望网页设计师浪费时间和理智试图让网站在浏览器上运行的日子已经结束。现在是最懒惰的客户/访客更新他们的旧浏览器的时候了。这并不难。即使是旧的和死的操作系统通常也有办法在它们上安装新版本的浏览器。如今,没有更新浏览器的人只占百分之一的一小部分。

例如,世界上最流行的移动/响应式网站框架 Bootstrap 框架关心支持所有主流浏览器的 2 个最新主要版本(至少 0.5% 的市场份额)。以下是他们目前的名单:

  • 0.5% 或更高的市场份额
  • 仅最后 2 个主要版本
  • 不是死浏览器(未停产)
  • 铬 >= 60
  • 火狐 >= 60
  • 火狐 ESR
  • iOS >= 12
  • 野生动物园 >= 12
  • not Explorer <= 11(意味着根本没有 Internet Explorer 版本)

我完全同意这一点。在 2000 年代初期,我是一名网络开发人员,那绝对是地狱。期望让它在一些随机的、愚蠢的用户的古老浏览器上运行是地狱。它带走了 Web 开发的所有乐趣。它让我讨厌退出了Web 开发。因为我 90% 的时间都浪费在浏览器兼容性上。这不是生活应该有的样子。一些顾客/访客懒惰不是你的错。这些天来,游客没有更多的借口保持懒惰。

相反,您应该只针对拥有现代浏览器的用户。这些天基本上是每个人。任何人都没有理由使用旧浏览器。如果他们使用旧的浏览器,你的网站应该显示一个又大又肥的横幅,上面写着“请为了你自己加入现代世界。下载一个新的浏览器。你怎么能用这么旧的浏览器过正常的生活?你是穴居人时代的时间旅行者吗?

人们再也没有借口使用旧浏览器了:

  1. Linux:默认附带最新版本的 Firefox。
  2. Mac:随 Safari 一起提供,这是一种现代浏览器。但是一些旧的 macOS 版本不会获得更新版本的 Safari,而且旧机器通常也无法安装最新的 macOS 版本。好吧,这些游客运气不好。他们不仅会在您的网站上遇到麻烦。他们可以安装现代浏览器(例如 Chrome),即使在旧版本的 macOS 上也能做到。所以他们没有任何借口。不要浪费你的生命去迎合那些使用非常老旧、漏洞百出的 Safari 版本的人。
  3. Windows:Windows 10 附带 Edge,它基于 Chromium,并且与 Chrome 一样与网站兼容。人们没有借口拥有旧浏览器。大多数 Windows 用户使用 Chrome。至于非常旧的、已停产的 Windows 版本(XP、Vista、7、8),好吧,我们再次遇到与以前相同的问题:您是否关心 0.0000001% 使用死操作系统和旧 Internet Explorer 的愚蠢访问者版本?无论如何,整个该死的网络都会被他们破坏,所以谁在乎你的网站是否也被他们破坏了他们应该停止偷懒,只需将他们的操作系统升级到 Windows 10,或者至少在他们当前的操作系统上安装 Chrome 或 Firefox。他们没有任何借口。
  4. iOS:如果您卡在超级旧的 iOS 设备上,那么您将无法使用现代网络。倒霉。很多网络都会为你而崩溃。获取新设备。甚至像世界排名第一的移动 Web 框架 Bootstrap 这样的框架也不支持 iOS 11 或更早版本。这不是我们的问题。如果他们仍然挂在这么旧的设备上,那就是小气鬼游客的问题。他们几乎可以不花钱就能得到一台更新的二手 iOS 设备,并解决他们在访问现代网络时遇到的所有问题。而且他们无论如何都需要购买它,因为大多数应用程序(甚至是银行/重要应用程序)都需要现代 iOS 版本。
  5. Android:浏览器独立于操作系统更新,甚至可以侧载,所以即使你被困在旧的 Android 版本上,你也可以使用现代浏览器。所以你没有任何借口。

如今,大多数人都拥有完全最新且自动更新的浏览器。这就是事实。

所以,是的……网站设计师仅仅为了迎合旧浏览器而受苦受难的日子已经结束了。因此我建议人们在他们的网站上使用 ES6 和 CSS3,让网页设计第一次成为一种乐趣。

希望你喜欢我提供的 ES6 函数!

于 2021-05-01T22:37:01.780 回答
0
function $(selector, base = null) {
  base = (base === null) ? document : base;
  return base.querySelector(selector);
}

function $$(selector, base = null) {
  base = (base === null) ? document : base;
  return base.querySelectorAll(selector);
}

为什么不更简单???:

let $ = (selector, base = document) => {
  let elements = base.querySelectorAll(selector);
  return (elements.length == 1) ? elements[0] : elements;
}
于 2019-10-08T12:57:21.640 回答