前言
说是冷门,无非于我们而言,在实际项目中登场的机会少,或许有些api压根没听说过,本篇介绍几个 api 算是冷门中的那几烁极光,在我们穷尽一切办法时,它或许带来那丝曙光。
Element.classList
Element.classList 是一个只读属性,返回一个元素的类属性的实时 DOMTokenList 集合。 相比将 element.className 作为以空格分隔的字符串来使用,classList 是一种更方便的访问元素的类列表的方法。常用相关的api如下:
- add : 添加指定的类值。如果这些类已经存在于元素的属性中,那么它们将被忽略。
- remove : 删除指定的类值。
- toggle :切换 class ; 即如果类存在,则删除它,如果不存在,则添加它。
- contain :检查元素的类属性中是否存在指定的类值
- replace :用一个新类替换已有类。
在 Element.classList
没用出现之前,我们可能这样操作DOM
/* 添加 class 类 方法*/
function add(element, className) {
if(!new RegExp("(^|\\s)" + className + "(\\s|$)").test(element.className)) element.className += ' ' + className;
}
/* 移出 class 类 方法*/
function remove(element, className) {
element.className = element.className.replace(new RegExp("(^|\\s)" + className + "(?=(\\s|$))", "g"), '');
}
/* 切换 class 类 方法*/
function toggle(element, className) {
if(new RegExp("(^|\\s)" + className + "(\\s|$)").test(element.className)){
element.className = element.className.replace(className,'')
}else{
element.className = element.className.trim() + ' ' + className;
}
}
/* 判断是否包含某个 class 类 方法*/
function contain(element, className) {
return element.className.indexOf(className)>-1
}
/* 用一个新类替换已有类*/
function replace(element, oldClassName,newClassName) {
element.className = element.className.replace(oldClassName,newClassName)
}
Element.classList
出现后,我们这样操作DOM
- 给元素添加一个 class 类
element.classList.add( className )
- 移除元素身上的一个 class 类
element.classList.remove( className )
- 切换元素身上的一个 class 类
element.classList.toggle( className )
- 判断元素身上是否包含一个 class 类
element.classList.contain( className )
- 用一个新类替换已有类
element.classList.replace( oldClass, newClass )
- 返回索引对应的类
//html <button class="a b c"> 按钮 </button>
document.querySelector('.a').classList.item(0) // a
document.querySelector('.a').classList.item(1) // b
document.querySelector('.a').classList.item(2) // c
document.querySelector('.a').classList.item(3) // null
Element.getBoundingClientRect
Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置
返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合,就是该元素的 CSS 边框大小。返回的结果是包含完整元素的最小矩形,并且拥有left, top, right, bottom, x, y, width, 和 height这几个以像素为单位的只读属性用于描述整个边框。除了width 和 height 以外的属性是相对于视图窗口的左上角来计算的。空边框盒(译者注:没有内容的边框)会被忽略。如果所有的元素边框都是空边框,那么这个矩形给该元素返回的 width、height 值为 0,left、top 值为第一个 CSS 盒子(按内容顺序)的 top-left 值。
当计算边界矩形时,会考虑视口区域(或其他可滚动元素)内的滚动操作,也就是说,当滚动位置发生了改变,top和left属性值就会随之立即发生变化(因此,它们的值是相对于视口的,而不是绝对的)。如果你需要获得相对于整个网页左上角定位的属性值,那么只要给top、left属性值加上当前的滚动位置(通过 window.scrollX 和 window.scrollY),这样就可以获取与当前的滚动位置无关的值 。源自 Element.getBoundingClientRect - MDN

我们可以获取这些数据进行我们的逻辑
function getBoundingClientRect (element) {
let rect = element.getBoundingClientRect();
return {
left: rect.left,//元素左边到视窗左边的距离
top: rect.top,//元素上边到视窗上边的距离
right: rect.right,//元素右边到视窗左边的距离
bottom: rect.bottom,//元素下边到视窗上边的距离
width: rect.width,//是元素自身的宽
height: rect.height//是元素自身的高
}
}
Element.insertAdjacentHTML
insertAdjacentHTML() 方法将指定的文本解析为 Element 元素,并将结果节点插入到DOM树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接使用innerHTML操作更快。
语法: element.insertAdjacentHTML(position, text)
- position
一个 DOMString,表示插入内容相对于元素的位置,并且必须是以下字符串之一:
beforebegin
:元素自身的前面。afterbegin
:插入元素内部的第一个子节点之前。beforeend
:插入元素内部的最后一个子节点之后。afterend
:元素自身的后面。
- text
是要被解析为HTML或XML元素,并插入到DOM树中的
DOMString
。
位置名称的可视化
<!-- beforebegin -->
<p>
<!-- afterbegin -->
foo
<!-- beforeend -->
</p>
<!-- afterend -->
注意: beforebegin和afterend位置,仅在节点在树中且节点具有一个parent元素时工作。
有时候,我们想要在页面的一个DOM元素里直接插入DOM字符串,想要jQuery的append的功能,能够往DOM里面注入DOM字符串
document.createElement实现
// html <ul id="ul"></div>
let ul = document.getElementById('ul');
for(let i=0;i<5;i++){
let li = document.createElement('li')
li.className = "item"
li.innerHTML = `<p>${item}</p>`
ul.appendChild(li)
}
从中可以看出,频繁操作DOM,对页面性能极不友好
element.insertAdjacentHTML实现
// html <ul id="ul"></div>
let ul = document.getElementById('ul');
let html = ''
for(let i=0;i<5;i++){
html +=`<li class="item"><p>${item}</p></li>`
}
ul.insertAdjacentHTML('beforeend',html)
只操作了一次DOM
安全问题
使用 insertAdjacentHTML 插入用户输入的HTML内容的时候,需要转义之后才能使用。
如果只是为了插入文本内容(而不是HTML节点),不建议使用这个方法,建议使用node.textContent 或者 node.insertAdjacentText()。因为这样不需要经过HTML解释器的转换,性能会好一点。
CustomEvent
CustomEvent 事件是由程序创建的,可以有任意自定义功能的事件。
CustomEvent是一个构造函数, 可以创建一个自定义事件,可以用 window.dispatchEvent
去主动触发这个自定义事件
使用示例:
实现localStorage 监听
- localStorage.setItem监听:自定义事件 setItemEvent
- localStorage.getItem监听:自定义事件 getItemEvent
- localStorage.removeItem监听:自定义事件 removeItemEvent
//监听自定义事件 setItemEvent
localStorage.setItem = (Orgin=>{
return function(key,value){
let setItemEvent = new CustomEvent('setItemEvent',{detail:{setKey:key,value}})
window.dispatchEvent(setItemEvent)
Orgin.call(this,key,typeof value == 'string'? value : JSON.stringify(value))
}
})(localStorage.setItem)
//监听自定义事件 getItemEvent
localStorage.getItem = (Orgin=>{
return function(key){
let result = JSON.parse(Orgin.call(this,key))
let getItemEvent = new CustomEvent('getItemEvent',{detail:{getKey:key,value:result}})
window.dispatchEvent(getItemEvent)
return result
}
})(localStorage.getItem)
//监听自定义事件 removeItemEvent
localStorage.removeItem = (Orgin=>{
return function(key){
let removeItemEvent = new CustomEvent('removeItemEvent',{detail:{removeKey:key}})
window.dispatchEvent(removeItemEvent)
Orgin.call(this,key)
}
})(localStorage.removeItem)
以上示例,我们对localStorage的
setItem
、getItem
、removeItem
在不影响本身的功能前提下进行了重写,让我们有了对这localStorage的这三个操作进行了监听的功能。
监听
//localStorage.setItem监听
window.addEventListener('setItemEvent',function(e){
console.log(e.detail)
})
//localStorage.getItem监听
window.addEventListener('getItemEvent',function(e){
console.log(e.detail)
})
//localStorage.removeItem监听
window.addEventListener('removeItemEvent',function(e){
console.log(e.detail)
})
该示例在混合app开发中有实际应用,原生安卓或原生IOS 与 我们的JS交互,有很大的帮助
ParentNode.append
ParentNode.append 方法在 ParentNode的最后一个子节点之后插入一组 Node 对象或 DOMString 对象。 被插入的 DOMString 对象等价为 Text 节点。
与 Node.appendChild() 的差异:
- ParentNode.append()允许追加 DOMString 对象,而 Node.appendChild() 只接受 Node 对象。
- ParentNode.append() 没有返回值,而 Node.appendChild() 返回追加的 Node 对象。
- ParentNode.append() 可以追加多个节点和字符串,而 Node.appendChild() 只能追加一个节点。
如果想要 DOM 插入 DOMString
,可以选用 element.insertAdjacentHTML(position, DOMString)
,如果想要即可以插入NODE节点也可以插入字符串,可以选用 ParentNode.append()
var parent = document.createElement("div");
var p = document.createElement("p");
parent.append("Some text", p);
console.log(parent);
// <div>"Some text"<p></p></div>
Document.createDocumentFragment
创建一个新的空白的文档片段( DocumentFragment)。
语法:let fragment = document.createDocumentFragment()
描述: fragment 是一个指向空DocumentFragment对象的引用。
DocumentFragments 是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。
因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。
示例:
HTML
<ul id="ul"></ul>
JavaScript
var element = document.getElementById('ul'); // assuming ul exists
var fragment = document.createDocumentFragment();
var browsers = ['Firefox', 'Chrome', 'Opera',
'Safari', 'Internet Explorer'];
browsers.forEach(function(browser) {
var li = document.createElement('li');
li.textContent = browser;
fragment.appendChild(li);
});
element.appendChild(fragment);
结果:
Firefox
Chrome
Opera
Safari
Internet Explorer
参考文献
结语
如果你有更好的点子,或者没有找到你想要的工具函数,欢迎留言
文中若有不准确或错误的地方,欢迎指出
往期文章 :