/*** 判断是否含有某个class** @export* @param {any} ele 元素* @param {any} cls class名* @returns*/export function hasClass (ele, cls) { cls = cls || '' if (cls.replace(/\s/g, '').length === 0) return false // 当cls没有参数时,返回false return new RegExp(' ' + cls + ' ').test(' ' + ele.className + ' ')}/*** 添加class** @export* @param {any} ele 元素* @param {any} cls 需要添加的class名*/export function addClass (ele, cls) { if (!hasClass(ele, cls)) { ele.className = ele.className === '' ? cls : ele.className + ' ' + cls }}/*** 移出class** @export* @param {any} ele 元素* @param {any} cls 需要移除的class名*/export function removeClass (ele, cls) { if (hasClass(ele, cls)) { var newClass = ' ' + ele.className.replace(/[\t\r\n]/g, '') + ' ' while (newClass.indexOf(' ' + cls + ' ') >= 0) { newClass = newClass.replace(' ' + cls + ' ', ' ') } ele.className = newClass.replace(/^\s+|\s+$/g, '') }}export function on (element, event, handler) { if (element && event) { element.addEventListener(event, handler, false) }}export function off (element, event, handler) { if (element && event) { element.removeEventListener(event, handler, false) }}
检查元素是否具有指定类
const hasClass = (el, className) => el.classList.contains(className);// 例子hasClass(document.querySelector('p.special'), 'special'); // true
添加类
const addClass = (el, className) => el.classList.add(className);// 例子addClass(document.querySelector('p'), 'special');// The paragraph will now have the 'special' class
删除类
const removeClass = (el, className) => el.classList.remove(className);// 例子removeClass(document.querySelector('p.special'), 'special');// The paragraph will not have the 'special' class anymore
获取元素样式
const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName];// 例子getStyle(document.querySelector('p'), 'font-size'); // '16px'
toggle切换类
const toggleClass = (el, className) => el.classList.toggle(className);// 例子toggleClass(document.querySelector('p.special'), 'special');// The paragraph will not have the 'special' class anymore
设置样式
const setStyle = (el, rule, val) => (el.style[rule] = val);// 例子setStyle(document.querySelector('p'), 'font-size', '20px');// The first <p> element on the page will have a font-size of 20px
指定元素添加样式
const addStyles = (el, styles) => Object.assign(el.style, styles);// 例子addStyles(document.getElementById('my-element'), { background: 'red', color: '#ffff00', fontSize: '3rem'});
渲染DOM
const renderElement = ({ type, props = {} }, container) => { const isTextElement = !type; const element = isTextElement ? document.createTextNode('') : document.createElement(type); const isListener = p => p.startsWith('on'); const isAttribute = p => !isListener(p) && p !== 'children'; Object.keys(props).forEach(p => { if (isAttribute(p)) element[p] = props[p]; if (!isTextElement && isListener(p)) element.addEventListener(p.toLowerCase().slice(2), props[p]); }); if (!isTextElement && props.children && props.children.length) props.children.forEach(childElement => renderElement(childElement, element) ); container.appendChild(element);};// 例子const myElement = { type: 'button', props: { type: 'button', className: 'btn', onClick: () => alert('Clicked'), children: [{ props: { nodeValue: 'Click me' } }] }};renderElement(myElement, document.body);
添加多个监听
const addMultipleListeners = (el, types, listener, options, useCapture) => { types.forEach(type => el.addEventListener(type, listener, options, useCapture) );};// 例子addMultipleListeners( document.querySelector('.my-element'), ['click', 'mousedown'], () => { console.log('hello!') });
仅监听一次
const listenOnce = (el, evt, fn) => el.addEventListener(evt, fn, { once: true });// 例子listenOnce( document.getElementById('my-id'), 'click', () => console.log('Hello world')); // 'Hello world' will only be logged on the first click
停止滚动监听
const onScrollStop = callback => { let isScrolling; window.addEventListener( 'scroll', e => { clearTimeout(isScrolling); isScrolling = setTimeout(() => { callback(); }, 150); }, false );};// 例子onScrollStop(() => { console.log('The user has stopped scrolling');});
点击指定元素范围外执行回调
const onClickOutside = (element, callback) => { document.addEventListener('click', e => { if (!element.contains(e.target)) callback(); });};// 例子onClickOutside('#my-element', () => console.log('Hello'));// Will log 'Hello' whenever the user clicks outside of #my-element
触发给定元素上的特定事件,可选传递自定义数据
const triggerEvent = (el, eventType, detail) => el.dispatchEvent(new CustomEvent(eventType, { detail }));// 例子triggerEvent(document.getElementById('myId'), 'click');triggerEvent(document.getElementById('myId'), 'click', { username: 'bob' });
获取元素到文档顶部的距离
const getVerticalOffset = el => { let offset = el.offsetTop, _el = el; while (_el.offsetParent) { _el = _el.offsetParent; offset += _el.offsetTop; } return offset;};// 例子getVerticalOffset('.my-element'); // 120
检测元素是否在视图中可见
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;};// 例子// 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)
全屏显示元素
const fullscreen = (mode = true, el = 'body') => mode ? document.querySelector(el).requestFullscreen() : document.exitFullscreen();// 例子fullscreen(); // Opens `body` in fullscreen modefullscreen(false); // Exits fullscreen mode