我将运行 document.querySelectorAll() 很多,并且想要一个简写别名。
var queryAll = document.querySelectorAll
queryAll('body')
TypeError: Illegal invocation
不工作。然而:
document.querySelectorAll('body')
仍然如此。如何使别名起作用?
我将运行 document.querySelectorAll() 很多,并且想要一个简写别名。
var queryAll = document.querySelectorAll
queryAll('body')
TypeError: Illegal invocation
不工作。然而:
document.querySelectorAll('body')
仍然如此。如何使别名起作用?
这似乎有效:
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);
一个常见的答案是使用$
and$$
和。这个别名模仿了 jQuery 的别名。querySelector
querySelectorAll
例子:
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>
JavaScript 解释器抛出错误,因为querySelectorAll()
应该在文档上下文中调用。
当您尝试调用console.log()
别名时会引发相同的错误。
所以你需要像这样包装它:
function x(selector) {
return document.querySelectorAll(selector);
}
我的解决方案涵盖以下四个用例:
编码:
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,返回所有这些元素的 nodeListqs("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>
这会起作用,您需要使用call()
或apply()
使用适当的上下文来调用别名。
func.call(context, arg1, arg2, ...)
func.apply(context, [args])
var x = document.querySelectorAll;
x.call(document, 'body');
x.apply(document, ['body']);
我采用了@David Muller 的方法,并使用 lambda 对其进行了单线化
let $ = (selector) => document.querySelector(selector);
let $all = (selector) => document.querySelectorAll(selector);
例子:
$('body');
// <body>...</body>
function x(expr)
{
return document.querySelectorAll(expr);
}
这是我的看法。如果选择器有多个匹配项,则返回 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);
}
如果您不关心支持没有人应该再使用的古老、糟糕的浏览器,那么您可以这样做:
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
确保函数变量不能被覆盖。(args) => code with implied return statement
{}
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% 的市场份额)。以下是他们目前的名单:
我完全同意这一点。在 2000 年代初期,我是一名网络开发人员,那绝对是地狱。期望让它在一些随机的、愚蠢的用户的古老浏览器上运行是地狱。它带走了 Web 开发的所有乐趣。它让我讨厌并退出了Web 开发。因为我 90% 的时间都浪费在浏览器兼容性上。这不是生活应该有的样子。一些顾客/访客懒惰不是你的错。这些天来,游客没有更多的借口保持懒惰。
相反,您应该只针对拥有现代浏览器的用户。这些天基本上是每个人。任何人都没有理由使用旧浏览器。如果他们使用旧的浏览器,你的网站应该显示一个又大又肥的横幅,上面写着“请为了你自己加入现代世界。下载一个新的浏览器。你怎么能用这么旧的浏览器过正常的生活?你是穴居人时代的时间旅行者吗?
人们再也没有借口使用旧浏览器了:
如今,大多数人都拥有完全最新且自动更新的浏览器。这就是事实。
所以,是的……网站设计师仅仅为了迎合旧浏览器而受苦受难的日子已经结束了。因此我建议人们在他们的网站上使用 ES6 和 CSS3,让网页设计第一次成为一种乐趣。
希望你喜欢我提供的 ES6 函数!
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;
}