Skip to content

Latest commit

 

History

History
1121 lines (803 loc) · 29.3 KB

Browser.md

File metadata and controls

1121 lines (803 loc) · 29.3 KB

contents

🌐 Browser

View contents

🌐 Browser

arrayToHtmlList

将给定的数组元素转换为<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');


⬆ 返回顶部

bottomVisible

如果页面底部可见,则返回“true”,否则返回“false”。

使用scrollYscrollHeightclientHeight来确定页面底部是否可见。

const bottomVisible = () =>
  document.documentElement.clientHeight + window.scrollY >=
  (document.documentElement.scrollHeight || document.documentElement.clientHeight);
Examples
bottomVisible(); // true


⬆ 返回顶部

copyToClipboard advanced

⚠️注意使用新的异步剪贴板API可以轻松实现相同的功能,该API仍然是实验性的,但将来应该使用而不是此片段。 了解更多信息这里

将字符串复制到剪贴板。 仅在用户操作的结果下工作(即在“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.


⬆ 返回顶部

counter advanced

创建具有指定选择器的指定范围,步长和持续时间的计数器。

检查step是否有正确的符号并相应更改。 将setInterval()Math.abs()Math.floor()结合使用,计算每次新文本绘制之间的时间。 使用document.querySelector().innerHTML来更新所选元素的值。 省略第四个参数step,使用默认步骤1。 省略第五个参数duration,使用默认的持续时间2000ms。

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"


⬆ 返回顶部

createElement

从字符串创建元素(不将其附加到文档)。 如果给定的字符串包含多个元素,则只返回第一个元素。

使用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'


⬆ 返回顶部

createEventHub advanced

使用emitonoff方法创建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);


⬆ 返回顶部

currentURL

返回当前URL。

使用window.location.href获取当前URL。

const currentURL = () => window.location.href;
Examples
currentURL(); // 'https://google.com'


⬆ 返回顶部

detectDeviceType

检测网站是在移动设备还是台式机/笔记本电脑中打开。

使用正则表达式测试navigator.userAgent属性,以确定设备是移动设备还是台式机/笔记本电脑。

const detectDeviceType = () =>
  /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
    ? 'Mobile'
    : 'Desktop';
Examples
detectDeviceType(); // "Mobile" or "Desktop"


⬆ 返回顶部

elementContains

如果parent元素包含child元素,则返回true,否则返回false

检查parentchild不是同一个元素,使用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


⬆ 返回顶部

elementIsVisibleInViewport advanced

如果指定的元素在视口中可见,则返回“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)


⬆ 返回顶部

formToObject

将一组表单元素编码为对象

使用FormData构造函数将HTMLform转换为FormDataArray.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' }


⬆ 返回顶部

getImages

从元素中获取所有图像并将它们放入数组中

使用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', '...']


⬆ 返回顶部

getScrollPosition

返回当前页面的滚动位置。

如果定义了pageXOffsetpageYOffset,则使用scrollLeftscrollTop。 您可以省略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}


⬆ 返回顶部

getStyle

返回指定元素的CSS规则的值。

使用Window.getComputedStyle()获取指定元素的CSS规则的值。

const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName];
Examples
getStyle(document.querySelector('p'), 'font-size'); // '16px'


⬆ 返回顶部

hasClass

如果元素具有指定的类,则返回“true”,否则返回“false”。

使用element.classList.contains()来检查元素是否具有指定的类。

const hasClass = (el, className) => el.classList.contains(className);
Examples
hasClass(document.querySelector('p.special'), 'special'); // true


⬆ 返回顶部

hashBrowser advanced

使用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'


⬆ 返回顶部

hide

隐藏指定的所有元素。

使用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


⬆ 返回顶部

httpsRedirect

如果页面当前处于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


⬆ 返回顶部

insertAfter

在指定元素结束后插入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>


⬆ 返回顶部

insertBefore

在指定元素的开头之前插入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>


⬆ 返回顶部

isBrowserTabFocused

如果页面的浏览器选项卡是聚焦的,则返回true,否则返回false

使用Page Visibility API引入的Document.hidden属性来检查页面的浏览器选项卡是可见还是隐藏。

const isBrowserTabFocused = () => !document.hidden;
Examples
isBrowserTabFocused(); // true


⬆ 返回顶部

nodeListToArray

NodeList转换为数组。

在新数组中使用spread运算符(扩展运算符...)将NodeList转换为数组。

const nodeListToArray = nodeList => [...nodeList];
Examples
nodeListToArray(document.childNodes); // [ <!DOCTYPE html>, html ]


⬆ 返回顶部

observeMutations advanced

返回一个新的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


⬆ 返回顶部

off

从元素中删除事件监听器。

使用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


⬆ 返回顶部

on

向具有使用事件委派功能的元素添加事件监听器。

使用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


⬆ 返回顶部

onUserInputChange advanced

每当用户输入类型改变时(mousetouch)运行回调。 用于根据输入设备启用/禁用代码。 该过程是动态的并且适用于混合设备(例如,触摸屏笔记本电脑)。

使用两个事件侦听器。 首先假设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.');
});


⬆ 返回顶部

prefix

返回浏览器支持的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'


⬆ 返回顶部

recordAnimationFrames

在每个动画帧上调用提供的回调。

使用递归。 如果runningtrue,则继续调用window.requestAnimationFrame(),它调用提供的回调。 使用两个方法startstop返回一个对象,以允许手动控制录制。 省略第二个参数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


⬆ 返回顶部

redirect

重定向到指定的URL。

使用window.location.hrefwindow.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');


⬆ 返回顶部

runAsync advanced

使用Web Worker在单独的线程中运行函数,允许长时间运行的函数不阻止UI。

使用Blob对象URL创建一个新的Worker,其内容应该是所提供函数的字符串化版本。 立即发布回调函数的返回值。 返回一个promise,侦听onmessageonerror事件并解析从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'


⬆ 返回顶部

scrollToTop

平滑滚动到页面顶部。

使用document.documentElement.scrollTopdocument.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();


⬆ 返回顶部

serializeForm

将一组表单元素编码为查询字符串。

使用FormData构造函数将HTMLform转换为FormDataArray.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


⬆ 返回顶部

setStyle

设置指定元素的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


⬆ 返回顶部

show

显示指定的所有元素。

使用扩展运算符(...)和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


⬆ 返回顶部

smoothScroll

平滑地将调用它的元素滚动到浏览器窗口的可见区域。

使用.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


⬆ 返回顶部

toggleClass

切换元素的类。

使用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


⬆ 返回顶部

triggerEvent

触发给定元素上的特定事件,可选地传递自定义数据。

使用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' });


⬆ 返回顶部

UUIDGeneratorBrowser

在浏览器中生成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'


⬆ 返回顶部