@txdfe/at
Version:
一个设计体系组件库
315 lines (265 loc) • 7.41 kB
JavaScript
;
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;
}
}