为document.querySelectorAll创建一个简短的别名

时间:2012-11-14 17:21:23

标签: javascript native-methods

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

var queryAll = document.querySelectorAll

queryAll('body')
TypeError: Illegal invocation

不起作用。鉴于:

document.querySelectorAll('body')

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

10 个答案:

答案 0 :(得分:74)

这似乎有效:

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

bind返回对querySelectorAll函数的引用,将querySelectorAll方法中'this'的上下文更改为文档对象。

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


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

var query = document.querySelector.bind(document);
var queryAll = document.querySelectorAll.bind(document);
var fromId = document.getElementById.bind(document);
var fromClass = document.getElementsByClassName.bind(document);
var fromTag = document.getElementsByTagName.bind(document);

答案 1 :(得分:14)

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

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

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

 function x(selector) {
     return document.querySelectorAll(selector);
 }

答案 2 :(得分:7)

这样可行,您需要使用call()apply()使用适当的上下文调用别名。

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

var x = document.querySelectorAll;
x.call(document, 'body');
x.apply(document, ['body']);

答案 3 :(得分:7)

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

  • 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):在第一个div的myContainer元素内查询,返回该元素
  • qsa("div", myContainer):在所有div的myContainer元素内查询,返回所有这些元素的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);};

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

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>

答案 4 :(得分:6)

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

示例:

&#13;
&#13;
$ = document.querySelector.bind(document)
$$ = document.querySelectorAll.bind(document)

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

答案 5 :(得分:4)

我采用了@David Muller的方法,并使用lambda将其排成一行

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

示例:

$('body');
// <body>...</body>

答案 6 :(得分:3)

function x(expr)
{
    return document.querySelectorAll(expr);
}

答案 7 :(得分:1)

这是我的看法。如果选择器具有多个匹配项,则返回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);
}

答案 8 :(得分: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 年之前的浏览器不支持)
  • 没有 {}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。不要担心那些使用旧浏览器的人。这是他们的问题,不是你的。

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

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

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

  • 0.5% 或更高的市场份额
  • 仅最新 2 个主要版本
  • 不是死浏览器(未停产)
  • Chrome >= 60
  • 火狐 >= 60
  • Firefox ESR
  • iOS >= 12
  • Safari >= 12
  • 不是 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 设备,那么您将无法使用现代网络。倒霉。很多网络都会被你破坏。获取新设备。即使是像 Bootstrap 这样世界排名第一的移动 Web 框架,也不支持 iOS 11 或更早版本。这不是我们的问题。如果他们仍然挂在这么旧的设备上,那就是小气鬼访客的问题。他们几乎可以免费获得一台更新的二手 iOS 设备,并解决访问现代网络的所有问题。而且他们无论如何都需要购买,因为大多数应用(甚至是银行/重要应用)都需要现代 iOS 版本。
  5. Android:浏览器独立于操作系统更新,甚至可以侧载,因此即使您停留在旧的 Android 版本上,您也可以访问现代浏览器。所以你没有任何借口。

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

所以是的......网站设计师只为迎合旧浏览器而受苦受难的日子已经结束。所以我建议大家在自己的网站上使用 ES6 和 CSS3,让网页设计第一次成为一种乐趣。

希望你喜欢我提供的 ES6 功能!

答案 9 :(得分: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;
}