View contents
arrayToHtmlList
bottomVisible
copyToClipboard
counter
createElement
createEventHub
currentURL
detectDeviceType
elementContains
elementIsVisibleInViewport
formToObject
getImages
getScrollPosition
getStyle
hasClass
hashBrowser
hide
httpsRedirect
insertAfter
insertBefore
isBrowserTabFocused
nodeListToArray
observeMutations
off
on
onUserInputChange
prefix
recordAnimationFrames
redirect
runAsync
scrollToTop
serializeForm
setStyle
show
smoothScroll
toggleClass
triggerEvent
UUIDGeneratorBrowser
将给定的数组元素转换为<li>
标记,并将它们附加到给定id的列表中。
使用Array.prototype.map()
,document.querySelector()
和一个匿名内部闭包来创建一个html标签列表。
const arrayToHtmlList = (arr, listID) =>
(el => (
(el = document.querySelector('#' + listID)),
(el.innerHTML += arr.map(item => `<li>${item}</li>`).join(''))
))();
Examples
arrayToHtmlList(['item 1', 'item 2'], 'myListID');
如果页面底部可见,则返回“true”,否则返回“false”。
使用scrollY
,scrollHeight
和clientHeight
来确定页面底部是否可见。
const bottomVisible = () =>
document.documentElement.clientHeight + window.scrollY >=
(document.documentElement.scrollHeight || document.documentElement.clientHeight);
Examples
bottomVisible(); // true
将字符串复制到剪贴板。 仅在用户操作的结果下工作(即在“click”事件监听器内)。
创建一个新的<textarea>
元素,用提供的数据填充它并将其添加到HTML文档中。
使用Selection.getRangeAt()
来存储选定的范围(如果有的话)。
使用document.execCommand('copy')
复制到剪贴板。
从HTML文档中删除<textarea>
元素。
最后,使用Selection()。addRange()
来恢复原始的选定范围(如果有的话)。
const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly', '');
el.style.position = 'absolute';
el.style.left = '-9999px';
document.body.appendChild(el);
const selected =
document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
el.select();
document.execCommand('copy');
document.body.removeChild(el);
if (selected) {
document.getSelection().removeAllRanges();
document.getSelection().addRange(selected);
}
};
Examples
copyToClipboard('Lorem ipsum'); // 'Lorem ipsum' copied to clipboard.
创建具有指定选择器的指定范围,步长和持续时间的计数器。
检查step
是否有正确的符号并相应更改。
将setInterval()
与Math.abs()
和Math.floor()
结合使用,计算每次新文本绘制之间的时间。
使用document.querySelector().innerHTML
来更新所选元素的值。
省略第四个参数step
,使用默认步骤1
。
省略第五个参数duration
,使用默认的持续时间2000
ms。
const counter = (selector, start, end, step = 1, duration = 2000) => {
let current = start,
_step = (end - start) * step < 0 ? -step : step,
timer = setInterval(() => {
current += _step;
document.querySelector(selector).innerHTML = current;
if (current >= end) document.querySelector(selector).innerHTML = end;
if (current >= end) clearInterval(timer);
}, Math.abs(Math.floor(duration / (end - start))));
return timer;
};
Examples
counter('#my-id', 1, 1000, 5, 2000); // Creates a 2-second timer for the element with id="my-id"
从字符串创建元素(不将其附加到文档)。 如果给定的字符串包含多个元素,则只返回第一个元素。
使用document.createElement()
创建一个新元素。
将其innerHTML
设置为作为参数提供的字符串。
使用ParentNode.firstElementChild
返回字符串的元素版本。
const createElement = str => {
const el = document.createElement('div');
el.innerHTML = str;
return el.firstElementChild;
};
Examples
const el = createElement(
`<div class="container">
<p>Hello!</p>
</div>`
);
console.log(el.className); // 'container'
使用emit
,on
和off
方法创建pub / sub(publish-subscribe)事件中心。
使用Object.create(null)
创建一个空的hub
对象,该对象不从Object.prototype
继承属性。
对于emit
,基于event
参数解析处理程序数组,然后通过传入数据作为参数,使用Array.prototype.forEach()
运行每个处理程序。
对于on
,如果事件尚不存在,则为该事件创建一个数组,然后使用Array.prototype.push()
添加处理程序
到阵列。
对于off
,使用Array.prototype.findIndex()
来查找事件数组中处理程序的索引,并使用Array.prototype.splice()
将其删除。
const createEventHub = () => ({
hub: Object.create(null),
emit(event, data) {
(this.hub[event] || []).forEach(handler => handler(data));
},
on(event, handler) {
if (!this.hub[event]) this.hub[event] = [];
this.hub[event].push(handler);
},
off(event, handler) {
const i = (this.hub[event] || []).findIndex(h => h === handler);
if (i > -1) this.hub[event].splice(i, 1);
if (this.hub[event].length === 0) delete this.hub[event];
}
});
Examples
const handler = data => console.log(data);
const hub = createEventHub();
let increment = 0;
// Subscribe: listen for different types of events
hub.on('message', handler);
hub.on('message', () => console.log('Message event fired'));
hub.on('increment', () => increment++);
// Publish: emit events to invoke all handlers subscribed to them, passing the data to them as an argument
hub.emit('message', 'hello world'); // logs 'hello world' and 'Message event fired'
hub.emit('message', { hello: 'world' }); // logs the object and 'Message event fired'
hub.emit('increment'); // `increment` variable is now 1
// Unsubscribe: stop a specific handler from listening to the 'message' event
hub.off('message', handler);
返回当前URL。
使用window.location.href
获取当前URL。
const currentURL = () => window.location.href;
Examples
currentURL(); // 'https://google.com'
检测网站是在移动设备还是台式机/笔记本电脑中打开。
使用正则表达式测试navigator.userAgent
属性,以确定设备是移动设备还是台式机/笔记本电脑。
const detectDeviceType = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
? 'Mobile'
: 'Desktop';
Examples
detectDeviceType(); // "Mobile" or "Desktop"
如果parent
元素包含child
元素,则返回true
,否则返回false
。
检查parent
与child
不是同一个元素,使用parent.contains(child)
来检查parent
元素是否包含child
元素。
const elementContains = (parent, child) => parent !== child && parent.contains(child);
Examples
elementContains(document.querySelector('head'), document.querySelector('title')); // true
elementContains(document.querySelector('body'), document.querySelector('body')); // false
如果指定的元素在视口中可见,则返回“true”,否则返回“false”。
使用Element.getBoundingClientRect()
和window.inner(Width | Height)
值
确定给定元素在视口中是否可见。
省略第二个参数以确定元素是否完全可见,或指定“true”以确定是否
它是部分可见的。
const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
const { top, left, bottom, right } = el.getBoundingClientRect();
const { innerHeight, innerWidth } = window;
return partiallyVisible
? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
};
Examples
// e.g. 100x100 viewport and a 10x10px element at position {top: -1, left: 0, bottom: 9, right: 10}
elementIsVisibleInViewport(el); // false - (not fully visible)
elementIsVisibleInViewport(el, true); // true - (partially visible)
将一组表单元素编码为对象
。
使用FormData
构造函数将HTMLform
转换为FormData
,Array.from()
转换为数组。
使用Array.prototype.reduce()
从数组中收集对象。
const formToObject = form =>
Array.from(new FormData(form)).reduce(
(acc, [key, value]) => ({
...acc,
[key]: value
}),
{}
);
Examples
formToObject(document.querySelector('#form')); // { email: 'test@email.com', name: 'Test Name' }
从元素中获取所有图像并将它们放入数组中
使用Element.prototype.getElementsByTagName()
来获取提供的元素中的所有<img>
元素,Array.prototype.map()
来映射它们各自的<img>
元素的每个src
属性, 然后创建一个Set
来消除重复并返回数组。
const getImages = (el, includeDuplicates = false) => {
const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src'));
return includeDuplicates ? images : [...new Set(images)];
};
Examples
getImages(document, true); // ['image1.jpg', 'image2.png', 'image1.png', '...']
getImages(document, false); // ['image1.jpg', 'image2.png', '...']
返回当前页面的滚动位置。
如果定义了pageXOffset
和pageYOffset
,则使用scrollLeft
和scrollTop
。
您可以省略el
来使用默认值window
。
const getScrollPosition = (el = window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
Examples
getScrollPosition(); // {x: 0, y: 200}
返回指定元素的CSS规则的值。
使用Window.getComputedStyle()
获取指定元素的CSS规则的值。
const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName];
Examples
getStyle(document.querySelector('p'), 'font-size'); // '16px'
如果元素具有指定的类,则返回“true”,否则返回“false”。
使用element.classList.contains()
来检查元素是否具有指定的类。
const hasClass = (el, className) => el.classList.contains(className);
Examples
hasClass(document.querySelector('p.special'), 'special'); // true
使用SHA-256算法为值创建哈希值。 返回一个promise。
使用SubtleCryptoAPI为给定值创建哈希。
const hashBrowser = val =>
crypto.subtle.digest('SHA-256', new TextEncoder('utf-8').encode(val)).then(h => {
let hexes = [],
view = new DataView(h);
for (let i = 0; i < view.byteLength; i += 4)
hexes.push(('00000000' + view.getUint32(i).toString(16)).slice(-8));
return hexes.join('');
});
Examples
hashBrowser(JSON.stringify({ a: 'a', b: [1, 2, 3, 4], foo: { c: 'bar' } })).then(console.log); // '04aa106279f5977f59f9067fa9712afc4aedc6f5862a8defc34552d8c7206393'
隐藏指定的所有元素。
使用NodeList.prototype.forEach()
将display:none
应用于指定的每个元素。
const hide = (...el) => [...el].forEach(e => (e.style.display = 'none'));
Examples
hide(document.querySelectorAll('img')); // Hides all <img> elements on the page
如果页面当前处于HTTP状态,则将页面重定向到HTTPS。 此外,按下后退按钮不会将其恢复到HTTP页面,因为它已在历史记录中替换。
使用location.protocol
来获取当前使用的协议。 如果它不是HTTPS,请使用location.replace()
将现有页面替换为页面的HTTPS版本。 使用location.href
获取完整地址,用String.prototype.split()
拆分它,并删除URL的协议部分。
const httpsRedirect = () => {
if (location.protocol !== 'https:') location.replace('https://' + location.href.split('//')[1]);
};
Examples
httpsRedirect(); // If you are on http://mydomain.com, you are redirected to https://mydomain.com
在指定元素结束后插入HTML字符串。
使用el.insertAdjacentHTML()
和'afterend'的位置来解析
htmlString并在
el`结束后插入它。
const insertAfter = (el, htmlString) => el.insertAdjacentHTML('afterend', htmlString);
Examples
insertAfter(document.getElementById('myId'), '<p>after</p>'); // <div id="myId">...</div> <p>after</p>
在指定元素的开头之前插入HTML字符串。
使用el.insertAdjacentHTML()
和'beforebegin'
的位置来解析htmlString
并在el
的开头之前插入它。
const insertBefore = (el, htmlString) => el.insertAdjacentHTML('beforebegin', htmlString);
Examples
insertBefore(document.getElementById('myId'), '<p>before</p>'); // <p>before</p> <div id="myId">...</div>
如果页面的浏览器选项卡是聚焦的,则返回true
,否则返回false
。
使用Page Visibility API引入的Document.hidden
属性来检查页面的浏览器选项卡是可见还是隐藏。
const isBrowserTabFocused = () => !document.hidden;
Examples
isBrowserTabFocused(); // true
将NodeList
转换为数组。
在新数组中使用spread
运算符(扩展运算符...
)将NodeList
转换为数组。
const nodeListToArray = nodeList => [...nodeList];
Examples
nodeListToArray(document.childNodes); // [ <!DOCTYPE html>, html ]
返回一个新的MutationObserver
,并为指定元素上的每个变异运行提供的回调。
使用MutationObserver
观察给定元素的突变。
使用Array.prototype.forEach()
为每个观察到的突变运行回调。
省略第三个参数options
,使用默认options(全部为true
)。
const observeMutations = (element, callback, options) => {
const observer = new MutationObserver(mutations => mutations.forEach(m => callback(m)));
observer.observe(
element,
Object.assign(
{
childList: true,
attributes: true,
attributeOldValue: true,
characterData: true,
characterDataOldValue: true,
subtree: true
},
options
)
);
return observer;
};
Examples
const obs = observeMutations(document, console.log); // Logs all mutations that happen on the page
obs.disconnect(); // Disconnects the observer and stops logging mutations on the page
从元素中删除事件监听器。
使用EventTarget.removeEventListener()
从元素中删除事件监听器。
省略第四个参数opts
使用false
或根据添加事件监听器时使用的选项指定它。
const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts);
Examples
const fn = () => console.log('!');
document.body.addEventListener('click', fn);
off(document.body, 'click', fn); // no longer logs '!' upon clicking on the page
向具有使用事件委派功能的元素添加事件监听器。
使用EventTarget.addEventListener()
向元素添加事件监听器。 如果有一个target
属性提供给options对象,请确保事件目标与指定的目标匹配,然后通过提供正确的this
上下文来调用回调。
返回对自定义委托者函数的引用,以便可以与off
一起使用。
省略opts
以默认为非委托行为和事件冒泡。
const on = (el, evt, fn, opts = {}) => {
const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e);
el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false);
if (opts.target) return delegatorFn;
};
Examples
const fn = () => console.log('!');
on(document.body, 'click', fn); // logs '!' upon clicking the body
on(document.body, 'click', fn, { target: 'p' }); // logs '!' upon clicking a `p` element child of the body
on(document.body, 'click', fn, { options: true }); // use capturing instead of bubbling
每当用户输入类型改变时(mouse
或touch
)运行回调。 用于根据输入设备启用/禁用代码。 该过程是动态的并且适用于混合设备(例如,触摸屏笔记本电脑)。
使用两个事件侦听器。 首先假设mouse
输入并将touchstart
事件监听器绑定到文档。
在touchstart
上,添加一个mousemove
事件监听器,使用performance.now()
监听在20ms内触发的两个连续mousemove
事件。
在任何一种情况下,使用输入类型作为参数运行回调。
const onUserInputChange = callback => {
let type = 'mouse',
lastTime = 0;
const mousemoveHandler = () => {
const now = performance.now();
if (now - lastTime < 20)
(type = 'mouse'), callback(type), document.removeEventListener('mousemove', mousemoveHandler);
lastTime = now;
};
document.addEventListener('touchstart', () => {
if (type === 'touch') return;
(type = 'touch'), callback(type), document.addEventListener('mousemove', mousemoveHandler);
});
};
Examples
onUserInputChange(type => {
console.log('The user is now using', type, 'as an input method.');
});
返回浏览器支持的CSS属性的前缀版本(如果需要)。
在供应商前缀字符串数组上使用Array.prototype.findIndex()
来测试document.body
是否在其CSSStyleDeclaration
对象中定义了其中一个,否则返回null
。
使用String.prototype.charAt()
和String.prototype.toUpperCase()
来大写属性,该属性将附加到供应商前缀字符串。
const prefix = prop => {
const capitalizedProp = prop.charAt(0).toUpperCase() + prop.slice(1);
const prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
const i = prefixes.findIndex(
prefix => typeof document.body.style[prefix ? prefix + capitalizedProp : prop] !== 'undefined'
);
return i !== -1 ? (i === 0 ? prop : prefixes[i] + capitalizedProp) : null;
};
Examples
prefix('appearance'); // 'appearance' on a supported browser, otherwise 'webkitAppearance', 'mozAppearance', 'msAppearance' or 'oAppearance'
在每个动画帧上调用提供的回调。
使用递归。
如果running
是true
,则继续调用window.requestAnimationFrame()
,它调用提供的回调。
使用两个方法start
和stop
返回一个对象,以允许手动控制录制。
省略第二个参数autoStart
,在调用函数时隐式调用start
。
const recordAnimationFrames = (callback, autoStart = true) => {
let running = true,
raf;
const stop = () => {
running = false;
cancelAnimationFrame(raf);
};
const start = () => {
running = true;
run();
};
const run = () => {
raf = requestAnimationFrame(() => {
callback();
if (running) run();
});
};
if (autoStart) start();
return { start, stop };
};
Examples
const cb = () => console.log('Animation frame fired');
const recorder = recordAnimationFrames(cb); // logs 'Animation frame fired' on each animation frame
recorder.stop(); // stops logging
recorder.start(); // starts again
const recorder2 = recordAnimationFrames(cb, false); // `start` needs to be explicitly called to begin recording frames
重定向到指定的URL。
使用window.location.href
或window.location.replace()
重定向到url
。
传递第二个参数来模拟链接点击(true
- 默认)或HTTP重定向(false
)。
const redirect = (url, asLink = true) =>
asLink ? (window.location.href = url) : window.location.replace(url);
Examples
redirect('https://google.com');
使用Web Worker在单独的线程中运行函数,允许长时间运行的函数不阻止UI。
使用Blob
对象URL创建一个新的Worker
,其内容应该是所提供函数的字符串化版本。
立即发布回调函数的返回值。
返回一个promise,侦听onmessage
和onerror
事件并解析从worker返回的数据,或者抛出错误。
const runAsync = fn => {
const worker = new Worker(
URL.createObjectURL(new Blob([`postMessage((${fn})());`]), {
type: 'application/javascript; charset=utf-8'
})
);
return new Promise((res, rej) => {
worker.onmessage = ({ data }) => {
res(data), worker.terminate();
};
worker.onerror = err => {
rej(err), worker.terminate();
};
});
};
Examples
const longRunningFunction = () => {
let result = 0;
for (let i = 0; i < 1000; i++)
for (let j = 0; j < 700; j++) for (let k = 0; k < 300; k++) result = result + i + j + k;
return result;
};
/*
NOTE: Since the function is running in a different context, closures are not supported.
The function supplied to `runAsync` gets stringified, so everything becomes literal.
All variables and functions must be defined inside.
*/
runAsync(longRunningFunction).then(console.log); // 209685000000
runAsync(() => 10 ** 3).then(console.log); // 1000
let outsideVariable = 50;
runAsync(() => typeof outsideVariable).then(console.log); // 'undefined'
平滑滚动到页面顶部。
使用document.documentElement.scrollTop
或document.body.scrollTop
与顶部保持距离。
滚动距离顶部一小部分距离。 使用window.requestAnimationFrame()
来动画滚动。
const scrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c / 8);
}
};
Examples
scrollToTop();
将一组表单元素编码为查询字符串。
使用FormData
构造函数将HTMLform
转换为FormData
,Array.from()
转换为数组,并将map函数作为第二个参数传递。
使用Array.prototype.map()
和window.encodeURIComponent()
来编码每个字段的值。
使用带有适当参数的Array.prototype.join()
来生成适当的查询字符串。
const serializeForm = form =>
Array.from(new FormData(form), field => field.map(encodeURIComponent).join('=')).join('&');
Examples
serializeForm(document.querySelector('#form')); // email=test%40email.com&name=Test%20Name
设置指定元素的CSS规则的值。
使用element.style
将指定元素的CSS规则值设置为val
。
const setStyle = (el, ruleName, val) => (el.style[ruleName] = val);
Examples
setStyle(document.querySelector('p'), 'font-size', '20px'); // The first <p> element on the page will have a font-size of 20px
显示指定的所有元素。
使用扩展运算符(...
)和Array.prototype.forEach()
清除指定的每个元素的display
属性。
const show = (...el) => [...el].forEach(e => (e.style.display = ''));
Examples
show(...document.querySelectorAll('img')); // Shows all <img> elements on the page
平滑地将调用它的元素滚动到浏览器窗口的可见区域。
使用.scrollIntoView
方法滚动元素。
将{behavior:'smooth'}
传递给.scrollIntoView
,使其顺畅滚动。
const smoothScroll = element =>
document.querySelector(element).scrollIntoView({
behavior: 'smooth'
});
Examples
smoothScroll('#fooBar'); // scrolls smoothly to the element with the id fooBar
smoothScroll('.fooBar'); // scrolls smoothly to the first element with a class of fooBar
切换元素的类。
使用element.classList.toggle()
来切换元素的指定类。
const toggleClass = (el, className) => el.classList.toggle(className);
Examples
toggleClass(document.querySelector('p.special'), 'special'); // The paragraph will not have the 'special' class anymore
触发给定元素上的特定事件,可选地传递自定义数据。
使用new CustomEvent()
从指定的eventType
和细节创建一个事件。
使用el.dispatchEvent()
来触发给定元素上新创建的事件。
如果您不想将自定义数据传递给触发事件,请省略第三个参数detail
。
const triggerEvent = (el, eventType, detail) =>
el.dispatchEvent(new CustomEvent(eventType, { detail }));
Examples
triggerEvent(document.getElementById('myId'), 'click');
triggerEvent(document.getElementById('myId'), 'click', { username: 'bob' });
在浏览器中生成UUID。
使用crypto
API生成符合RFC4122版本4的UUID。
const UUIDGeneratorBrowser = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
);
Examples
UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d'