import isElement from './isElement';
import isUndefined from './isUndefined';
import isArray from './isArray';
/**
* @typedef {Object} DomElementInfo 包含了 Dom 信息获取和设置方法的对象
* @property {Function} addClass <strong>addClass (className:String)->void</strong><br>为 Dom 元素添加样式类名
* @property {Function} removeClass <strong>removeClass(className:String)->void</strong><br>为 Dom 元素删除样式类名
* @property {Function} hasClass <strong>hasClass(className:String)->Boolean </strong><br>检测 Dom 元素是否具有指定样式类名
* @property {Function} attr <strong>attr(key:String,?value:String)->String|null </strong><br>获取和设置 Dom 元素属性。当只传 key 不传 value 时,方法获取元素中名为 key 的属性值。当传了 key 和 value 时,方法为 dom 元素设置名为 key 值为 value 的属性。
* @property {Function} offset <strong>offset()->{left:Number,top:Number} </strong><br>获取 Dom 元素相对浏览器窗口左上角的偏移位置
* @property {Function} getSize <strong>getSize()->{width:NUmber, height:Number} </strong><br>获取 Dom 元素的宽高
* @property {Function} getStyle <strong>getStyle(property:String)->String </strong><br>获取 Dom 元素的指定样式的值,如: getStyle('width')
*/
/**
* @category Dom
* @param {Element} dom 传入的 dom 元素
* @returns {DomElementInfo} 元素信息对象,用于获取元素信息
* @function ry
* @example
* var a = document.getElementById('banner');
* var b =ry(a);
* b.addClass('banner-style');
* // => <h1 id='banner' class='banner-style'> hello world </h1>
*/
export default function ry(dom) {
return new DomElementInfo(dom);
}
var DomElementInfo = function (dom) {
this.ele = dom;
};
var siblings = function (n, elem) {
var matched = [];
for (; n; n = n.nextSibling) {
if (n.nodeType === 1 && n !== elem) {
matched.push(n);
}
}
return matched;
};
DomElementInfo.prototype = {
addClass: function (para) {
var classes = ' ' + this.ele.className + ' ';
if (classes.indexOf(' ' + para + ' ') === -1) {
this.ele.className = this.ele.className + (this.ele.className === '' ? '' : ' ') + para;
}
return this;
},
removeClass: function (para) {
var classes = ' ' + this.ele.className + ' ';
if (classes.indexOf(' ' + para + ' ') !== -1) {
this.ele.className = classes.replace(' ' + para + ' ', ' ').slice(1, -1);
}
return this;
},
hasClass: function (para) {
var classes = ' ' + this.ele.className + ' ';
if (classes.indexOf(' ' + para + ' ') !== -1) {
return true;
} else {
return false;
}
},
attr: function (key, value) {
if (typeof key === 'string' && isUndefined(value)) {
return this.ele.getAttribute(key);
}
if (typeof key === 'string') {
value = String(value);
this.ele.setAttribute(key, value);
}
return this;
},
offset: function () {
try {
var rect = this.ele.getBoundingClientRect();
var doc = this.ele.ownerDocument;
var docElem = doc.documentElement;
return {
top: rect.top + window.pageYOffset - docElem.clientTop,
left: rect.left + window.pageXOffset - docElem.clientLeft
};
} catch (e) {
return {
top: 0,
left: 0
};
}
},
getSize: function () {
if (!window.getComputedStyle) {
return { width: this.ele.offsetWidth, height: this.ele.offsetHeight };
}
try {
var bounds = this.ele.getBoundingClientRect();
return { width: bounds.width, height: bounds.height };
} catch (e) {
return { width: 0, height: 0 };
}
},
getStyle: function (value) {
if (this.ele.currentStyle) {
return this.ele.currentStyle[value];
} else {
return this.ele.ownerDocument.defaultView.getComputedStyle(this.ele, null).getPropertyValue(value);
}
},
wrap: function (elementTagName) {
var ele = document.createElement(elementTagName);
this.ele.parentNode.insertBefore(ele, this.ele);
ele.appendChild(this.ele);
return ry(ele);
},
getCssStyle: function (prop) {
var result = this.ele.style.getPropertyValue(prop);
if (result) {
return result;
}
var rules = null;
if (typeof window.getMatchedCSSRules === 'function') {
rules = window.getMatchedCSSRules(this.ele);
}
if (!rules || !isArray(rules)) {
return null;
}
for (var i = rules.length - 1; i >= 0; i--) {
var r = rules[i];
result = r.style.getPropertyValue(prop);
if (result) {
return result;
}
}
},
sibling: function (cur, dir) {
//eslint-disable-next-line
while ((cur = cur[dir]) && cur.nodeType !== 1) { }
return cur;
},
next: function () {
return this.sibling(this.ele, 'nextSibling');
},
prev: function () {
return this.sibling(this.ele, 'previousSibling');
},
siblings: function () {
return siblings((this.ele.parentNode || {}).firstChild, this.ele);
},
children: function () {
return siblings(this.ele.firstChild);
},
parent: function () {
var parent = this.ele.parentNode;
parent = parent && parent.nodeType !== 11 ? parent : null;
return ry(parent);
},
// 兼容原生不支持 previousElementSibling 的旧版浏览器
previousElementSibling: function () {
var el = this.ele;
if ('previousElementSibling' in document.documentElement) {
return ry(el.previousElementSibling);
} else {
while ((el = el.previousSibling)) {
if (el.nodeType === 1) {
return ry(el);
}
}
return ry(null);
}
},
// 得到和当前元素相同类型的同级元素
getSameTypeSiblings: function () {
var element = this.ele;
var parentNode = element.parentNode;
var tagName = element.tagName.toLowerCase();
var arr = [];
for (var i = 0; i < parentNode.children.length; i++) {
var child = parentNode.children[i];
if (child.nodeType === 1 && child.tagName.toLowerCase() === tagName) {
arr.push(parentNode.children[i]);
}
}
return arr;
},
//获取元素 path
getParents: function () {
try {
var element = this.ele;
if (!isElement(element)) {
return [];
}
var pathArr = [element];
if (element === null || element.parentElement === null) {
return [];
}
while (element.parentElement !== null) {
element = element.parentElement;
pathArr.push(element);
}
return pathArr;
} catch (err) {
return [];
}
}
};
Source