UNPKG

@txdfe/at

Version:

一个设计体系组件库

315 lines (265 loc) 7.41 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.addClass = addClass; exports.forceReflow = forceReflow; exports.getOffset = getOffset; exports.getStyle = getStyle; exports.hasClass = hasClass; exports.matches = exports.hasDOM = void 0; exports.removeClass = removeClass; exports.scrollbar = scrollbar; exports.setStyle = setStyle; exports.toggleClass = toggleClass; var _string = require("./string"); var _object = require("./object"); function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } /** * 是否能使用 DOM 方法 * @type {Boolean} */ var hasDOM = typeof window !== 'undefined' && !!window.document && !!document.createElement; /** * 节点是否包含指定 className * @param {Element} node * @param {String} className * @return {Boolean} * * @example * dom.hasClass(document.body, 'foo'); */ exports.hasDOM = hasDOM; function hasClass(node, className) { /* istanbul ignore if */ if (!hasDOM || !node) { return false; } if (node.classList) { return node.classList.contains(className); } else { return node.className.indexOf(className) > -1; } } /** * 添加 className * @param {Element} node * @param {String} className * * @example * dom.addClass(document.body, 'foo'); */ function addClass(node, className, _force) { /* istanbul ignore if */ if (!hasDOM || !node) { return; } if (node.classList) { node.classList.add(className); } else if (_force === true || !hasClass(node, className)) { node.className += " ".concat(className); } } /** * 移除 className * @param {Element} node * @param {String} className * * @example * dom.removeClass(document.body, 'foo'); */ function removeClass(node, className, _force) { /* istanbul ignore if */ if (!hasDOM || !node) { return; } if (node.classList) { node.classList.remove(className); } else if (_force === true || hasClass(node, className)) { node.className = node.className.replace(className, '').replace(/\s+/g, ' ').trim(); } } /** * 切换 className * @param {Element} node * @param {String} className * @return {Boolean} 执行后节点上是否还有此 className * * @example * dom.toggleClass(document.body, 'foo'); */ function toggleClass(node, className) { /* istanbul ignore if */ if (!hasDOM || !node) { return false; } if (node.classList) { return node.classList.toggle(className); } else { var flag = hasClass(node, className); flag ? removeClass(node, className, true) : addClass(node, className, true); return !flag; } } /** * 元素是否匹配 CSS 选择器 * @param {Element} node DOM 节点 * @param {String} selector CSS 选择器 * @return {Boolean} * * @example * dom.matches(mountNode, '.container'); // boolean */ var matches = function () { var matchesFn = null; /* istanbul ignore else */ if (hasDOM) { var _body = document.body || document.head; matchesFn = _body.matches ? 'matches' : _body.webkitMatchesSelector ? 'webkitMatchesSelector' : _body.msMatchesSelector ? 'msMatchesSelector' : _body.mozMatchesSelector ? 'mozMatchesSelector' : null; } return function (node, selector) { if (!hasDOM || !node) { return false; } return matchesFn ? node[matchesFn](selector) : false; }; }(); /** * 获取元素计算后的样式 * @private * @param {Element} node * @return {Object} */ exports.matches = matches; function _getComputedStyle(node) { return node && node.nodeType === 1 ? window.getComputedStyle(node, null) : {}; } var PIXEL_PATTERN = /margin|padding|width|height|max|min|offset|size/i; var removePixel = { left: 1, top: 1, right: 1, bottom: 1 }; /** * 校验并修正元素的样式属性值 * @private * @param {Element} node * @param {String} type * @param {Number} value */ function _getStyleValue(node, type, value) { type = type.toLowerCase(); if (value === 'auto') { if (type === 'height') { return node.offsetHeight || 0; } if (type === 'width') { return node.offsetWidth || 0; } } if (!(type in removePixel)) { // 属性值是否需要去掉 px 单位,这里假定此类的属性值都是 px 为单位的 removePixel[type] = PIXEL_PATTERN.test(type); } return removePixel[type] ? parseFloat(value) || 0 : value; } var floatMap = { cssFloat: 1, styleFloat: 1, "float": 1 }; /** * 获取元素计算后的样式 * @param {Element} node DOM 节点 * @param {String} name 属性名 * @return {Number|Object} */ function getStyle(node, name) { /* istanbul ignore if */ if (!hasDOM || !node) { return null; } var style = _getComputedStyle(node); // 如果不指定属性名,则返回全部值 if (arguments.length === 1) { return style; } name = floatMap[name] ? 'cssFloat' in node.style ? 'cssFloat' : 'styleFloat' : name; return _getStyleValue(node, name, style.getPropertyValue((0, _string.hyphenate)(name)) || node.style[(0, _string.camelcase)(name)]); } /** * 设置元素的样式 * @param {Element} node DOM 节点 * @param {Object|String} name 属性名,或者是一个对象,包含多个属性 * @param {Number|String} value 属性值 * * @example * // 设置单个属性值 * dom.setStyle(mountNode, 'width', 100); * // 设置多条属性值 * dom.setStyle(mountNode, { * width: 100, * height: 200 * }); */ function setStyle(node, name, value) { /* istanbul ignore if */ if (!hasDOM || !node) { return false; } // 批量设置多个值 if (_typeof(name) === 'object' && arguments.length === 2) { (0, _object.each)(name, function (val, key) { return setStyle(node, key, val); }); } else { name = floatMap[name] ? 'cssFloat' in node.style ? 'cssFloat' : 'styleFloat' : name; if (typeof value === 'number' && PIXEL_PATTERN.test(name)) { value = "".concat(value, "px"); } node.style[(0, _string.camelcase)(name)] = value; // IE8 support } } /** * 获取默认的滚动条大小 * @return {Object} width, height */ function scrollbar() { var scrollDiv = document.createElement('div'); setStyle(scrollDiv, { position: 'absolute', width: '100px', height: '100px', overflow: 'scroll', top: '-9999px' }); document.body.appendChild(scrollDiv); var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; var scrollbarHeight = scrollDiv.offsetHeight - scrollDiv.clientHeight; document.body.removeChild(scrollDiv); return { width: scrollbarWidth, height: scrollbarHeight }; } /** * 获取元素距离视口顶部和左边的偏移距离 * @return {Object} top, left */ function getOffset(node) { var rect = node.getBoundingClientRect(); var win = node.ownerDocument.defaultView; return { top: rect.top + win.pageYOffset, left: rect.left + win.pageXOffset }; } /** * 强制访问元素的布局属性以触发重排,通常用于保证动画的执行 * @param {Element} el * @return {void} */ function forceReflow(el) { if (el) { el.offsetHeight; } }