更加方便的 querySelector
原链接 https://www.cnblogs.com/chun6/p/7053053.html
背景
每次我们都需要下面这样写添加点击事件,相当的繁琐,而我们又不甘心用 jQuery,那么怎么办呢?
var btn = document.querySelector("#xxid");btn.addEventListener("click", (e) => { console.log(e);});
解决方案
抛砖
我们都应该稍微接触过一些 jQuery,它的格式大概是这样:
$("#xxid").click(function () { $(this).hide();});
所以我们肯定会尝试这样去写
let $ = document.querySelector;let btn = $("#xxid");
但是测试之后,我们开始怀疑人生。
Uncaught TypeError: Illegal invocation
这里报错的原因是 querySelectorAll
所需的执行上下文必需是 document
,而我们赋值到 $
调用后上下文变成了全局 window
。
引玉
经过上面的分析,我们将代码改成了这样
let $ = document.querySelector.bind(document);Element.prototype.$on = Element.prototype.addEventListener;
$("#xxid").$on("click", (e) => { console.log(e); });
于是,我们的代码变得相当的精简,有了一分 jQuery 的味道。
Tips
同样的,我们可以写更多的方法
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);
然而,通过 query 获得的节点可以是单个或多个节点,而我们不能直接用 map
和 foreach
来操作 NodeList,正确的操作姿势应该是:
Array.prototype.map.call(document.querySelectorAll('button'), (element,index) => { element.onclick = function () { // Your code here }})
引出新的问题
写习惯 TypeScript 之后,发现用这种方式没有自动补全,好难受啊。
Selector 的类型还是比较好声明的,可以用如下的方式声明
/** @type {typeof document.querySelector} */let $ = document.querySelector.bind(document);
然而,$on
就很难直接用 jsdoc 声明类型了,恐怕只能用 d.ts
来声明了。
interface Element { $on(type: string, listener: (event: Event) => void, options?: boolean | AddEventListenerOptions): void;}