DOMUtils

使用js重新对jQuery的部分函数进行了仿写

当前为 2023-12-15 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/465772/1296209/DOMUtils.js

  1. /**
  2. * 自己常用的元素工具类
  3. * @copyright GPL-3.0-only
  4. * @author WhiteSev
  5. **/
  6. (function (global, factory) {
  7. /**
  8. * 不使用define
  9. * typeof define === "function" && define.amd
  10. * define(factory)
  11. */
  12. if (typeof exports === "object" && typeof module !== "undefined") {
  13. /* 适用于NodeJs或typeScript */
  14. module.exports = factory();
  15. } else {
  16. global = typeof globalThis !== "undefined" ? globalThis : global || self;
  17. /* 适用于浏览器中,且this对象是window,如果this是其它,那么会在其它对象下注册(不可用)对象 */
  18. global.DOMUtils = factory(global.DOMUtils);
  19. }
  20. })(typeof window !== "undefined" ? window : this, function (AnotherDOMUtils) {
  21. const DOMUtils = {};
  22. /**
  23. * @type {string} 元素工具类的版本
  24. */
  25. DOMUtils.version = "2023-12-15";
  26.  
  27. let CommonUtils = {
  28. /**
  29. * 用于显示元素并获取它的高度宽度等其它属性
  30. * @param {HTMLElement} element
  31. * @returns {{recovery: Function}} - 恢复
  32. */
  33. showElement: function (element) {
  34. let oldCSS_display = element.style.display;
  35. let oldCSS_visibility = element.style.visibility;
  36. let oldCSS_position = element.style.position;
  37. element.style.display = "block";
  38. element.style.visibility = "hidden";
  39. element.style.position = "absolute";
  40. return {
  41. recovery() {
  42. element.style.display = oldCSS_display;
  43. element.style.visibility = oldCSS_visibility;
  44. element.style.position = oldCSS_position;
  45. },
  46. };
  47. },
  48. /**
  49. * 判断是否是window,例如window、self、globalThis
  50. * @param {any} target
  51. * @returns {boolean}
  52. */
  53. isWin(target) {
  54. if (!typeof target === "object") {
  55. return false;
  56. }
  57. if (target instanceof Node) {
  58. return false;
  59. }
  60. if (target === globalThis) {
  61. return true;
  62. }
  63. if (target === window) {
  64. return true;
  65. }
  66. if (target === self) {
  67. return true;
  68. }
  69. if (target?.Math?.toString() !== "[object Math]") {
  70. return false;
  71. }
  72. return true;
  73. },
  74. };
  75. /**
  76. * 获取或设置元素的属性值
  77. * @param {HTMLElement|string} element 目标元素
  78. * @param {string} attrName 属性名
  79. * @param {string} [attrValue] 属性值(可选)
  80. * @returns {?string} 如果传入了attrValue,则返回undefined;否则返回属性值
  81. * @example
  82. * // 获取a.xx元素的href属性
  83. * DOMUtils.attr(document.querySelector("a.xx"),"href");
  84. * DOMUtils.attr("a.xx","href");
  85. * > https://xxxx....
  86. * @example
  87. * // 修改a.xx元素的href属性为abcd
  88. * DOMUtils.attr(document.querySelector("a.xx"),"href","abcd");
  89. * DOMUtils.attr("a.xx","href","abcd");
  90. * */
  91. DOMUtils.attr = function (element, attrName, attrValue) {
  92. if (typeof element === "string") {
  93. element = document.querySelector(element);
  94. }
  95. if (element == void 0) {
  96. return;
  97. }
  98. if (attrValue === void 0) {
  99. return element.getAttribute(attrName);
  100. } else {
  101. element.setAttribute(attrName, attrValue);
  102. }
  103. };
  104.  
  105. /**
  106. * 创建元素
  107. * @param {string} tagName 元素类型
  108. * @param {HTMLElement|undefined} property 元素属性
  109. * @returns {HTMLElement}
  110. * @example
  111. * // 创建一个DIV元素,且属性class为xxx
  112. * DOMUtils.createElement("div",{ class:"xxx" });
  113. * > <div class="xxx"></div>
  114. * @example
  115. * // 创建一个DIV元素
  116. * DOMUtils.createElement("div");
  117. * > <div></div>
  118. * @example
  119. * // 创建一个DIV元素
  120. * DOMUtils.createElement("div","测试");
  121. * > <div>测试</div>
  122. */
  123. DOMUtils.createElement = function (tagName, property) {
  124. let tempElement = document.createElement(tagName);
  125. if (typeof property === "string") {
  126. tempElement.innerHTML = property;
  127. return tempElement;
  128. }
  129. if (property == void 0) {
  130. return tempElement;
  131. }
  132. Object.keys(property).forEach((key) => {
  133. if (key in tempElement || typeof property[key] === "object") {
  134. tempElement[key] = property[key];
  135. } else {
  136. tempElement.setAttribute(key, property[key]);
  137. }
  138. });
  139. return tempElement;
  140. };
  141.  
  142. /**
  143. * 获取或设置元素的样式属性值
  144. * @param {HTMLElement|string} element 目标元素
  145. * @param {CSSStyleDeclaration|string} property 样式属性名或包含多个属性名和属性值的对象
  146. * @param {any} [value] 样式属性值(可选)
  147. * @returns {?string} 如果传入了value,则返回undefined;否则返回样式属性值
  148. * @example
  149. * // 获取元素a.xx的CSS属性display
  150. * DOMUtils.css(document.querySelector("a.xx"),"display");
  151. * DOMUtils.css("a.xx","display");
  152. * > "none"
  153. * @example
  154. * // 设置元素a.xx的CSS属性display为block
  155. * DOMUtils.css(document.querySelector("a.xx"),"display","block");
  156. * DOMUtils.css(document.querySelector("a.xx"),"display","block !important");
  157. * DOMUtils.css(document.querySelector("a.xx"),{ display: "block" }});
  158. * DOMUtils.css(document.querySelector("a.xx"),{ display: "block !important" }});
  159. * DOMUtils.css("a.xx","display","block");
  160. * DOMUtils.css("a.xx","display","block !important");
  161. * @example
  162. * // 设置元素a.xx的CSS属性top为10px
  163. * DOMUtils.css(document.querySelector("a.xx"),"top","10px");
  164. * DOMUtils.css(document.querySelector("a.xx"),"top",10);
  165. * DOMUtils.css(document.querySelector("a.xx"),{ top: "10px" });
  166. * DOMUtils.css(document.querySelector("a.xx"),{ top: 10 });
  167. * */
  168. DOMUtils.css = function (element, property, value) {
  169. /**
  170. * 把纯数字没有px的加上
  171. */
  172. function handlePixe(propertyName, propertyValue) {
  173. let allowAddPixe = [
  174. "width",
  175. "height",
  176. "top",
  177. "left",
  178. "right",
  179. "bottom",
  180. "font-size",
  181. ];
  182. if (typeof propertyValue === "number") {
  183. propertyValue = propertyValue.toString();
  184. }
  185. if (
  186. typeof propertyValue === "string" &&
  187. allowAddPixe.includes(propertyName) &&
  188. propertyValue.match(/[0-9]$/gi)
  189. ) {
  190. propertyValue = propertyValue + "px";
  191. }
  192. return propertyValue;
  193. }
  194. if (typeof element === "string") {
  195. element = document.querySelector(element);
  196. }
  197. if (element == void 0) {
  198. return;
  199. }
  200. if (typeof property === "string") {
  201. if (value === void 0) {
  202. return getComputedStyle(element).getPropertyValue(property);
  203. } else {
  204. if (value === "string" && value.includes("!important")) {
  205. element.style.setProperty(property, value, "important");
  206. } else {
  207. value = handlePixe(property, value);
  208. element.style.setProperty(property, value);
  209. }
  210. }
  211. } else if (typeof property === "object") {
  212. for (let prop in property) {
  213. if (
  214. typeof property[prop] === "string" &&
  215. property[prop].includes("!important")
  216. ) {
  217. element.style.setProperty(prop, property[prop], "important");
  218. } else {
  219. property[prop] = handlePixe(prop, property[prop]);
  220. element.style.setProperty(prop, property[prop]);
  221. }
  222. }
  223. }
  224. };
  225. /**
  226. * 获取或设置元素的文本内容
  227. * @param {HTMLElement} element 目标元素
  228. * @param {HTMLElement|string} [text] 文本内容(可选)
  229. * @returns {?string} 如果传入了text,则返回undefined;否则返回文本内容
  230. * @example
  231. * // 设置元素a.xx的文本内容为abcd
  232. * DOMUtils.text(document.querySelector("a.xx"),"abcd")
  233. * DOMUtils.text("a.xx","abcd")
  234. * DOMUtils.html("a.xx",document.querySelector("b"))
  235. * */
  236. DOMUtils.text = function (element, text) {
  237. if (typeof element === "string") {
  238. element = document.querySelector(element);
  239. }
  240. if (element == void 0) {
  241. return;
  242. }
  243. if (text === void 0) {
  244. return element.textContent || element.innerText;
  245. } else {
  246. if (text instanceof Node) {
  247. text = text.textContent || text.innerText;
  248. }
  249. if ("textContent" in element) {
  250. element.textContent = text;
  251. } else if ("innerText" in element) {
  252. element.innerText = text;
  253. }
  254. }
  255. };
  256. /**
  257. * 获取或设置元素的HTML内容
  258. * @param {HTMLElement|string} element 目标元素
  259. * @param {HTMLElement|string} [html] HTML内容|元素(可选)
  260. * @returns {?string} 如果传入了html,则返回undefined;否则返回HTML内容
  261. * @example
  262. * // 设置元素a.xx的文本内容为<b>abcd</b>
  263. * DOMUtils.html(document.querySelector("a.xx"),"<b>abcd</b>")
  264. * DOMUtils.html("a.xx","<b>abcd</b>")
  265. * DOMUtils.html("a.xx",document.querySelector("b"))
  266. * */
  267. DOMUtils.html = function (element, html) {
  268. if (typeof element === "string") {
  269. element = document.querySelector(element);
  270. }
  271. if (element == void 0) {
  272. return;
  273. }
  274. if (html == void 0) {
  275. return element.innerHTML;
  276. } else {
  277. if (html instanceof Node) {
  278. html = html.innerHTML;
  279. }
  280. if ("innerHTML" in element) {
  281. element.innerHTML = html;
  282. }
  283. }
  284. };
  285. /**
  286. * 绑定或触发元素的click事件
  287. * @param {HTMLElement|string} element 目标元素
  288. * @param {function} [handler] 事件处理函数(可选)
  289. * @param {object|undefined} details 赋予触发的Event的额外属性
  290. * @param {boolean} [useDispatchToTriggerEvent=true] 是否使用dispatchEvent来触发事件,默认true
  291. * @example
  292. * // 触发元素a.xx的click事件
  293. * DOMUtils.click(document.querySelector("a.xx"))
  294. * DOMUtils.click("a.xx")
  295. * DOMUtils.click("a.xx",function(){
  296. * console.log("触发click事件成功")
  297. * })
  298. * */
  299. DOMUtils.click = function (
  300. element,
  301. handler,
  302. details,
  303. useDispatchToTriggerEvent = true
  304. ) {
  305. if (typeof element === "string") {
  306. element = document.querySelector(element);
  307. }
  308. if (element == void 0) {
  309. return;
  310. }
  311. if (handler === void 0) {
  312. DOMUtils.trigger(element, "click", details, useDispatchToTriggerEvent);
  313. } else {
  314. DOMUtils.on(element, "click", null, handler);
  315. }
  316. };
  317.  
  318. /**
  319. * 绑定或触发元素的blur事件
  320. * @param {HTMLElement|string} element 目标元素
  321. * @param {function} [handler] 事件处理函数(可选)
  322. * @param {object|undefined} details 赋予触发的Event的额外属性
  323. * @param {boolean} [useDispatchToTriggerEvent=true] 是否使用dispatchEvent来触发事件,默认true
  324. * @example
  325. * // 触发元素a.xx的blur事件
  326. * DOMUtils.blur(document.querySelector("a.xx"))
  327. * DOMUtils.blur("a.xx")
  328. * DOMUtils.blur("a.xx",function(){
  329. * console.log("触发blur事件成功")
  330. * })
  331. * */
  332. DOMUtils.blur = function (
  333. element,
  334. handler,
  335. details,
  336. useDispatchToTriggerEvent = true
  337. ) {
  338. if (typeof element === "string") {
  339. element = document.querySelector(element);
  340. }
  341. if (element == void 0) {
  342. return;
  343. }
  344. if (handler === void 0) {
  345. DOMUtils.trigger(element, "blur", details, useDispatchToTriggerEvent);
  346. } else {
  347. DOMUtils.on(element, "blur", null, handler);
  348. }
  349. };
  350. /**
  351. * 绑定或触发元素的focus事件
  352. * @param {HTMLElement|string|window} element 目标元素
  353. * @param {?function} [handler] 事件处理函数(可选)
  354. * @param {object|undefined} details 赋予触发的Event的额外属性
  355. * @param {boolean} [useDispatchToTriggerEvent=true] 是否使用dispatchEvent来触发事件,默认true
  356. * @example
  357. * // 触发元素a.xx的focus事件
  358. * DOMUtils.focus(document.querySelector("a.xx"))
  359. * DOMUtils.focus("a.xx")
  360. * DOMUtils.focus("a.xx",function(){
  361. * console.log("触发focus事件成功")
  362. * })
  363. * */
  364. DOMUtils.focus = function (
  365. element,
  366. handler,
  367. details,
  368. useDispatchToTriggerEvent = true
  369. ) {
  370. if (typeof element === "string") {
  371. element = document.querySelector(element);
  372. }
  373. if (element == void 0) {
  374. return;
  375. }
  376. if (handler === void 0) {
  377. DOMUtils.trigger(element, "focus", details, useDispatchToTriggerEvent);
  378. } else {
  379. DOMUtils.on(element, "focus", null, handler);
  380. }
  381. };
  382. /**
  383. * 获取或设置元素的value属性值
  384. * @param {HTMLElement|string} element 目标元素
  385. * @param {string} [value] value属性值(可选)
  386. * @returns {string|undefined} 如果传入了value,则返回undefined;否则返回value属性值
  387. * @example
  388. * // 获取元素input.xx的复选框值
  389. * DOMUtils.val(document.querySelector("input.xx"))
  390. * DOMUtils.val("input.xx")
  391. * > true
  392. * @example
  393. * // 修改元素input.xx的复选框值为true
  394. * DOMUtils.val(document.querySelector("input.xx"),true)
  395. * DOMUtils.val("input.xx",true)
  396. * */
  397. DOMUtils.val = function (element, value) {
  398. if (typeof element === "string") {
  399. element = document.querySelector(element);
  400. }
  401. if (element == void 0) {
  402. return;
  403. }
  404. if (value == void 0) {
  405. if (
  406. element.localName === "input" &&
  407. (element.type === "checkbox" || element.type === "radio")
  408. ) {
  409. return element.checked;
  410. } else {
  411. return element.value;
  412. }
  413. } else {
  414. if (
  415. element.localName === "input" &&
  416. (element.type === "checkbox" || element.type === "radio")
  417. ) {
  418. element.checked = !!value;
  419. } else {
  420. element.value = value;
  421. }
  422. }
  423. };
  424. /**
  425. * 获取或设置元素的属性值
  426. * @param {HTMLElement|string} element 目标元素
  427. * @param {string} propName 属性名
  428. * @param {string} [propValue] 属性值(可选)
  429. * @returns {string|undefined} 如果传入了propValue,则返回undefined;否则返回属性值
  430. * @example
  431. * // 获取元素a.xx的属性data-value
  432. * DOMUtils.val(document.querySelector("a.xx"),"data-value")
  433. * DOMUtils.val("a.xx","data-value")
  434. * > undefined
  435. * @example
  436. * // 设置元素a.xx的属性data-value为1
  437. * DOMUtils.val(document.querySelector("a.xx"),"data-value",1)
  438. * DOMUtils.val("a.xx","data-value",1)
  439. * */
  440. DOMUtils.prop = function (element, propName, propValue) {
  441. if (typeof element === "string") {
  442. element = document.querySelector(element);
  443. }
  444. if (element == void 0) {
  445. return;
  446. }
  447. if (propValue == void 0) {
  448. return element[propName];
  449. } else {
  450. element[propName] = propValue;
  451. }
  452. };
  453.  
  454. /**
  455. * 移除元素的属性
  456. * @param {HTMLElement|string} element 目标元素
  457. * @param {string} attrName 属性名
  458. * @example
  459. * // 移除元素a.xx的属性data-value
  460. * DOMUtils.removeAttr(document.querySelector("a.xx"),"data-value")
  461. * DOMUtils.removeAttr("a.xx","data-value")
  462. * */
  463. DOMUtils.removeAttr = function (element, attrName) {
  464. if (typeof element === "string") {
  465. element = document.querySelector(element);
  466. }
  467. if (element == void 0) {
  468. return;
  469. }
  470. element.removeAttribute(attrName);
  471. };
  472.  
  473. /**
  474. * 移除元素class名
  475. * @param {HTMLElement|string} element 目标元素
  476. * @param {string} className class名
  477. * @returns {DOMUtils} 原型链
  478. * @example
  479. * // 移除元素a.xx的className为xx
  480. * DOMUtils.removeClass(document.querySelector("a.xx"),"xx")
  481. * DOMUtils.removeClass("a.xx","xx")
  482. */
  483. DOMUtils.removeClass = function (element, className) {
  484. if (typeof element === "string") {
  485. element = document.querySelector(element);
  486. }
  487. if (element == void 0) {
  488. return;
  489. }
  490. if (className == void 0) {
  491. return;
  492. }
  493. element.classList.remove(className);
  494. };
  495.  
  496. /**
  497. * 移除元素的属性
  498. * @param {HTMLElement|string} element 目标元素
  499. * @param {string} propName 属性名
  500. * @example
  501. * // 移除元素a.xx的href属性
  502. * DOMUtils.removeProp(document.querySelector("a.xx"),"href")
  503. * DOMUtils.removeProp("a.xx","href")
  504. * */
  505. DOMUtils.removeProp = function (element, propName) {
  506. if (typeof element === "string") {
  507. element = document.querySelector(element);
  508. }
  509. if (element == void 0) {
  510. return;
  511. }
  512. delete element[propName];
  513. };
  514.  
  515. /**
  516. * 将一个元素替换为另一个元素
  517. * @param {HTMLElement|string} element 目标元素
  518. * @param {HTMLElement|string} newElement 新元素
  519. * @returns {DOMUtils} 原型链
  520. * @example
  521. * // 替换元素a.xx为b.xx
  522. * DOMUtils.replaceWith(document.querySelector("a.xx"),document.querySelector("b.xx"))
  523. * DOMUtils.replaceWith("a.xx",'<b class="xx"></b>')
  524. */
  525. DOMUtils.replaceWith = function (element, newElement) {
  526. if (typeof element === "string") {
  527. element = document.querySelector(element);
  528. }
  529. if (element == void 0) {
  530. return;
  531. }
  532. if (typeof newElement === "string") {
  533. newElement = DOMUtils.parseHTML(newElement, false, false);
  534. }
  535. if (element instanceof NodeList || element instanceof Array) {
  536. element.forEach((item) => {
  537. DOMUtils.replaceWith(item, newElement);
  538. });
  539. } else {
  540. element.parentElement.replaceChild(newElement, element);
  541. }
  542. };
  543.  
  544. /**
  545. * 给元素添加class
  546. * @param {HTMLElement|string} element 目标元素
  547. * @param {string} className class名
  548. * @example
  549. * // 元素a.xx的className添加_vue_
  550. * DOMUtils.addClass(document.querySelector("a.xx"),"_vue_")
  551. * DOMUtils.addClass("a.xx","_vue_")
  552. * */
  553. DOMUtils.addClass = function (element, className) {
  554. if (typeof element === "string") {
  555. element = document.querySelector(element);
  556. }
  557. if (element == void 0) {
  558. return;
  559. }
  560. element.classList.add(className);
  561. };
  562. /**
  563. * 函数在元素内部末尾添加子元素或HTML字符串
  564. * @param {HTMLElement|string} element 目标元素
  565. * @param {HTMLElement|string} content 子元素或HTML字符串
  566. * @example
  567. * // 元素a.xx的内部末尾添加一个元素
  568. * DOMUtils.append(document.querySelector("a.xx"),document.querySelector("b.xx"))
  569. * DOMUtils.append("a.xx","'<b class="xx"></b>")
  570. * */
  571. DOMUtils.append = function (element, content) {
  572. if (typeof element === "string") {
  573. element = document.querySelector(element);
  574. }
  575. if (element == void 0) {
  576. return;
  577. }
  578. if (typeof content === "string") {
  579. element.insertAdjacentHTML("beforeend", content);
  580. } else {
  581. element.appendChild(content);
  582. }
  583. };
  584.  
  585. /**
  586. * 函数 在元素内部开头添加子元素或HTML字符串
  587. * @param {HTMLElement|string} element 目标元素
  588. * @param {HTMLElement|string} content 子元素或HTML字符串
  589. * @example
  590. * // 元素a.xx内部开头添加一个元素
  591. * DOMUtils.prepend(document.querySelector("a.xx"),document.querySelector("b.xx"))
  592. * DOMUtils.prepend("a.xx","'<b class="xx"></b>")
  593. * */
  594. DOMUtils.prepend = function (element, content) {
  595. if (typeof element === "string") {
  596. element = document.querySelector(element);
  597. }
  598. if (element == void 0) {
  599. return;
  600. }
  601. if (typeof content === "string") {
  602. element.insertAdjacentHTML("afterbegin", content);
  603. } else {
  604. element.insertBefore(content, element.firstChild);
  605. }
  606. };
  607. /**
  608. * 在元素后面添加兄弟元素或HTML字符串
  609. * @param {HTMLElement|string} element 目标元素
  610. * @param {HTMLElement|string} content 兄弟元素或HTML字符串
  611. * @example
  612. * // 元素a.xx后面添加一个元素
  613. * DOMUtils.after(document.querySelector("a.xx"),document.querySelector("b.xx"))
  614. * DOMUtils.after("a.xx","'<b class="xx"></b>")
  615. * */
  616. DOMUtils.after = function (element, content) {
  617. if (typeof element === "string") {
  618. element = document.querySelector(element);
  619. }
  620. if (element == void 0) {
  621. return;
  622. }
  623. if (typeof content === "string") {
  624. element.insertAdjacentHTML("afterend", content);
  625. } else {
  626. element.parentElement.insertBefore(content, element.nextSibling);
  627. }
  628. };
  629.  
  630. /**
  631. * 在元素前面添加兄弟元素或HTML字符串
  632. * @param {HTMLElement|string} element 目标元素
  633. * @param {HTMLElement|string} content 兄弟元素或HTML字符串
  634. * @example
  635. * // 元素a.xx前面添加一个元素
  636. * DOMUtils.before(document.querySelector("a.xx"),document.querySelector("b.xx"))
  637. * DOMUtils.before("a.xx","'<b class="xx"></b>")
  638. * */
  639. DOMUtils.before = function (element, content) {
  640. if (typeof element === "string") {
  641. element = document.querySelector(element);
  642. }
  643. if (element == void 0) {
  644. return;
  645. }
  646. if (typeof content === "string") {
  647. element.insertAdjacentHTML("beforebegin", content);
  648. } else {
  649. element.parentElement.insertBefore(content, element);
  650. }
  651. };
  652.  
  653. /**
  654. * 移除元素
  655. * @param {HTMLElement|string|NodeList} element 目标元素
  656. * @example
  657. * // 元素a.xx前面添加一个元素
  658. * DOMUtils.remove(document.querySelector("a.xx"))
  659. * DOMUtils.remove(document.querySelectorAll("a.xx"))
  660. * DOMUtils.remove("a.xx")
  661. * */
  662. DOMUtils.remove = function (element) {
  663. if (typeof element === "string") {
  664. element = document.querySelectorAll(element);
  665. }
  666. if (element == void 0) {
  667. return;
  668. }
  669. if (element instanceof NodeList || element instanceof Array) {
  670. element.forEach(function (item) {
  671. DOMUtils.remove(item);
  672. });
  673. } else {
  674. element.remove();
  675. }
  676. };
  677. /**
  678. * 移除元素的所有子元素
  679. * @param {HTMLElement|string} element 目标元素
  680. * @example
  681. * // 移除元素a.xx元素的所有子元素
  682. * DOMUtils.empty(document.querySelector("a.xx"))
  683. * DOMUtils.empty("a.xx")
  684. * */
  685. DOMUtils.empty = function (element) {
  686. if (typeof element === "string") {
  687. element = document.querySelector(element);
  688. }
  689. if (element == void 0) {
  690. return;
  691. }
  692. while (element.firstChild) {
  693. element.removeChild(element.firstChild);
  694. }
  695. };
  696. /**
  697. * 绑定事件
  698. * @param {HTMLElement|string|NodeList|Array|Window} element 需要绑定的元素|元素数组|window
  699. * @param {string|[...string]} eventType 需要监听的事件
  700. * @param {string|undefined} selector 子元素选择器
  701. * @param {(event: Event)=>{}|undefined} callback 绑定事件触发的回调函数
  702. * @param {boolean} [capture=false] 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
  703. * @param {boolean} [once=false] 表示事件是否只触发一次。默认为false
  704. * @param {boolean} [passive=false] 表示事件监听器是否不会调用preventDefault()。默认为false
  705. * @example
  706. * // 监听元素a.xx的click事件
  707. * DOMUtils.on(document.querySelector("a.xx"),"click",(event)=>{
  708. * console.log("事件触发",event)
  709. * })
  710. * DOMUtils.on("a.xx","click",(event)=>{
  711. * console.log("事件触发",event)
  712. * })
  713. * @example
  714. * // 监听元素a.xx的click、tap、hover事件
  715. * DOMUtils.on(document.querySelector("a.xx"),"click tap hover",(event)=>{
  716. * console.log("事件触发",event)
  717. * })
  718. * DOMUtils.on("a.xx",["click","tap","hover"],(event)=>{
  719. * console.log("事件触发",event)
  720. * })
  721. * @example
  722. * // 监听全局document下的子元素a.xx的click事件
  723. * DOMUtils.on(document,"click tap hover","a.xx",(event)=>{
  724. * console.log("事件触发",event)
  725. * })
  726. */
  727. DOMUtils.on = function (
  728. element,
  729. eventType,
  730. selector,
  731. callback,
  732. capture = false,
  733. once = false,
  734. passive = false
  735. ) {
  736. if (typeof element === "string") {
  737. element = document.querySelectorAll(element);
  738. }
  739. if (element == void 0) {
  740. return;
  741. }
  742. let elementList = [];
  743. if (element instanceof NodeList || Array.isArray(element)) {
  744. elementList = [...element];
  745. } else {
  746. elementList = [element];
  747. }
  748. let eventTypeList = [];
  749. if (Array.isArray(eventType)) {
  750. eventTypeList = eventType;
  751. } else if (typeof eventType === "string") {
  752. eventTypeList = eventType.split(" ");
  753. }
  754. if (typeof selector === "function") {
  755. /* 这是为没有selector的情况 */
  756. callback = selector;
  757. selector = null;
  758. }
  759. elementList.forEach((elementItem) => {
  760. let ownCallBack = function (event) {
  761. if (selector) {
  762. let target = event.target;
  763. let totalParent = CommonUtils.isWin(elementItem)
  764. ? document.documentElement
  765. : elementItem;
  766. if (target.matches(selector)) {
  767. /* 当前目标可以被selector所匹配到 */
  768. callback.call(target, event);
  769. return;
  770. } else if (
  771. target.closest(selector) &&
  772. totalParent.contains(target.closest(selector))
  773. ) {
  774. /* 在上层与主元素之间寻找可以被selector所匹配到的 */
  775. let closestElement = target.closest(selector);
  776. /* event的target值不能直接修改 */
  777. Object.defineProperty(event, "target", {
  778. get: function () {
  779. return closestElement;
  780. },
  781. });
  782. callback.call(closestElement, event);
  783. return;
  784. }
  785. } else {
  786. callback.call(event.target, event);
  787. }
  788. };
  789. eventTypeList.forEach((_eventType_) => {
  790. elementItem.addEventListener(
  791. _eventType_,
  792. ownCallBack,
  793. capture,
  794. once,
  795. passive
  796. );
  797. });
  798.  
  799. if (callback && callback.delegate) {
  800. elementItem.setAttribute("data-delegate", selector);
  801. }
  802. if (CommonUtils.isWin(elementItem)) {
  803. let events = elementItem["DOMUtilsGlobalEvents"] || {};
  804. events[eventType] = events[eventType] || [];
  805. events[eventType].push({
  806. selector: selector,
  807. callback: ownCallBack,
  808. originCallBack: callback,
  809. });
  810. elementItem["DOMUtilsGlobalEvents"] = events;
  811. } else {
  812. let events = elementItem.events || {};
  813. events[eventType] = events[eventType] || [];
  814. events[eventType].push({
  815. selector: selector,
  816. callback: ownCallBack,
  817. originCallBack: callback,
  818. });
  819. elementItem.events = events;
  820. }
  821. });
  822. };
  823. /**
  824. * 取消绑定事件
  825. * @param {HTMLElement|string|NodeList|Array|Window} element 需要取消绑定的元素|元素数组
  826. * @param {string|[...string]} eventType 需要取消监听的事件
  827. * @param {string|undefined} selector 子元素选择器
  828. * @param {Function|undefined} callback 通过DOMUtils.on绑定的事件函数
  829. * @param {boolean} [useCapture=false] 表示事件是否在捕获阶段处理,它是一个可选参数,默认为false,表示在冒泡阶段处理事件。
  830. * 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
  831. * @example
  832. * // 取消监听元素a.xx的click事件
  833. * DOMUtils.off(document.querySelector("a.xx"),"click")
  834. * DOMUtils.off("a.xx","click")
  835. * // 取消监听元素a.xx的click、tap、hover事件
  836. * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
  837. * DOMUtils.off("a.xx",["click","tap","hover"])
  838. * // 取消监听全局下的a.xx的点击事件
  839. * DOMUtils.off(document,"click","a.xx")
  840. */
  841. DOMUtils.off = function (
  842. element,
  843. eventType,
  844. selector,
  845. callback,
  846. useCapture = false
  847. ) {
  848. if (typeof element === "string") {
  849. element = document.querySelectorAll(element);
  850. }
  851. if (element == void 0) {
  852. return;
  853. }
  854. let elementList = [];
  855. if (element instanceof NodeList || Array.isArray(element)) {
  856. elementList = [...element];
  857. } else {
  858. elementList = [element];
  859. }
  860. let eventTypeList = [];
  861. if (!eventType) {
  862. for (let type in events) {
  863. eventTypeList = [...eventTypeList, type];
  864. }
  865. } else if (Array.isArray(eventType)) {
  866. eventTypeList = eventType;
  867. } else if (typeof eventType === "string") {
  868. eventTypeList = eventType.split(" ");
  869. }
  870. if (typeof selector === "function") {
  871. /* 这是为没有selector的情况 */
  872. callback = selector;
  873. selector = null;
  874. }
  875. elementList.forEach((elementItem) => {
  876. let events = {};
  877. if (CommonUtils.isWin(elementItem)) {
  878. events = elementItem["DOMUtilsGlobalEvents"] || {};
  879. } else {
  880. events = elementItem.events || {};
  881. }
  882. eventTypeList.forEach((_eventType_) => {
  883. let handlers = events[eventType] || [];
  884. for (let i = 0; i < handlers.length; i++) {
  885. if (
  886. (!selector || handlers[i].selector === selector) &&
  887. (!callback ||
  888. handlers[i].callback === callback ||
  889. handlers[i].originCallBack === callback)
  890. ) {
  891. elementItem.removeEventListener(
  892. _eventType_,
  893. handlers[i].callback,
  894. useCapture
  895. );
  896. handlers.splice(i--, 1);
  897. }
  898. }
  899. if (handlers.length === 0) {
  900. delete events[eventType];
  901. }
  902. });
  903. if (CommonUtils.isWin(elementItem)) {
  904. elementItem["DOMUtilsGlobalEvents"] = events;
  905. } else {
  906. elementItem.events = events;
  907. }
  908. });
  909. };
  910.  
  911. /**
  912. * 主动触发事件
  913. * @param {HTMLElement|string|NodeList|Array|Window} element 需要触发的元素|元素数组|window
  914. * @param {string|[...string]} eventType 需要触发的事件
  915. * @param {object|undefined} details 赋予触发的Event的额外属性
  916. * @param {boolean} [useDispatchToTriggerEvent=true] 是否使用dispatchEvent来触发事件,默认true
  917. * @example
  918. * // 触发元素a.xx的click事件
  919. * DOMUtils.trigger(document.querySelector("a.xx"),"click")
  920. * DOMUtils.trigger("a.xx","click")
  921. * // 触发元素a.xx的click、tap、hover事件
  922. * DOMUtils.trigger(document.querySelector("a.xx"),"click tap hover")
  923. * DOMUtils.trigger("a.xx",["click","tap","hover"])
  924. */
  925. DOMUtils.trigger = function (
  926. element,
  927. eventType,
  928. details,
  929. useDispatchToTriggerEvent = true
  930. ) {
  931. if (typeof element === "string") {
  932. element = document.querySelector(element);
  933. }
  934. if (element == void 0) {
  935. return;
  936. }
  937. let elementList = [];
  938. if (element instanceof NodeList || Array.isArray(element)) {
  939. elementList = [...element];
  940. } else {
  941. elementList = [element];
  942. }
  943. let eventTypeList = [];
  944. if (!eventType) {
  945. for (let type in events) {
  946. eventTypeList = [...eventTypeList, type];
  947. }
  948. } else if (Array.isArray(eventType)) {
  949. eventTypeList = eventType;
  950. } else if (typeof eventType === "string") {
  951. eventTypeList = eventType.split(" ");
  952. }
  953.  
  954. elementList.forEach((elementItem) => {
  955. let events = {};
  956. if (CommonUtils.isWin(elementItem)) {
  957. events = elementItem["DOMUtilsGlobalEvents"] || {};
  958. } else {
  959. events = elementItem.events || {};
  960. }
  961. eventTypeList.forEach((_eventType_) => {
  962. let event = new Event(_eventType_);
  963. if (details) {
  964. Object.assign(event, details);
  965. }
  966. if (useDispatchToTriggerEvent == false && _eventType_ in events) {
  967. events[_eventType_].forEach((eventsItem) => {
  968. eventsItem.callback(event);
  969. });
  970. } else {
  971. elementItem.dispatchEvent(event);
  972. }
  973. });
  974. });
  975. };
  976. /**
  977. * 设置或返回被选元素相对于文档的偏移坐标
  978. * @param {HTMLElement|string} element
  979. * @returns { {
  980. * top: number,
  981. * left: number
  982. * }}
  983. * @example
  984. * // 获取元素a.xx的对于文档的偏移坐标
  985. * DOMUtils.offset(document.querySelector("a.xx"))
  986. * DOMUtils.offset("a.xx")
  987. * > 0
  988. */
  989. DOMUtils.offset = function (element) {
  990. if (typeof element === "string") {
  991. element = document.querySelector(element);
  992. }
  993. if (element == void 0) {
  994. return;
  995. }
  996. let rect = element.getBoundingClientRect();
  997. let win = window;
  998. return {
  999. top: rect.top + win.scrollY,
  1000. left: rect.left + win.scrollX,
  1001. };
  1002. };
  1003. /**
  1004. * 获取元素的宽度
  1005. * @param {HTMLElement|string} element 要获取宽度的元素
  1006. * @returns {number} 元素的宽度,单位为像素
  1007. * @example
  1008. * // 获取元素a.xx的宽度
  1009. * DOMUtils.width(document.querySelector("a.xx"))
  1010. * DOMUtils.width("a.xx")
  1011. * > 100
  1012. * // 获取window的宽度
  1013. * DOMUtils.width(window)
  1014. * > 400
  1015. * @example
  1016. * // 设置元素a.xx的宽度为200
  1017. * DOMUtils.width(document.querySelector("a.xx"),200)
  1018. * DOMUtils.width("a.xx",200)
  1019. */
  1020. DOMUtils.width = function (element) {
  1021. if (CommonUtils.isWin(element)) {
  1022. return window.document.documentElement.clientWidth;
  1023. }
  1024. if (typeof element === "string") {
  1025. element = document.querySelector(element);
  1026. }
  1027. if (element == void 0) {
  1028. return;
  1029. }
  1030. if (element.nodeType === 9) {
  1031. /* 文档节点 */
  1032. return Math.max(
  1033. element.body.scrollWidth,
  1034. element.documentElement.scrollWidth,
  1035. element.body.offsetWidth,
  1036. element.documentElement.offsetWidth,
  1037. element.documentElement.clientWidth
  1038. );
  1039. }
  1040. let handleElement = CommonUtils.showElement(element);
  1041. let view = element.ownerDocument.defaultView;
  1042. if (!view || !view.opener) {
  1043. view = window;
  1044. }
  1045. let styles = view.getComputedStyle(element);
  1046. let elementPaddingLeft = parseFloat(styles.paddingLeft);
  1047. let elementPaddingRight = parseFloat(styles.paddingRight);
  1048. if (isNaN(elementPaddingLeft)) {
  1049. elementPaddingLeft = 0;
  1050. }
  1051. if (isNaN(elementPaddingRight)) {
  1052. elementPaddingRight = 0;
  1053. }
  1054. let elementWidth =
  1055. element.clientWidth - elementPaddingLeft - elementPaddingRight;
  1056. handleElement.recovery();
  1057. return elementWidth;
  1058. };
  1059. /**
  1060. * 获取元素的高度
  1061. * @param {HTMLElement|string} element 要获取高度的元素
  1062. * @returns {number} 元素的高度,单位为像素
  1063. * @example
  1064. * // 获取元素a.xx的高度
  1065. * DOMUtils.height(document.querySelector("a.xx"))
  1066. * DOMUtils.height("a.xx")
  1067. * > 100
  1068. * // 获取window的高度
  1069. * DOMUtils.height(window)
  1070. * > 700
  1071. * @example
  1072. * // 设置元素a.xx的高度为200
  1073. * DOMUtils.height(document.querySelector("a.xx"),200)
  1074. * DOMUtils.height("a.xx",200)
  1075. */
  1076. DOMUtils.height = function (element) {
  1077. if (CommonUtils.isWin(element)) {
  1078. return window.document.documentElement.clientHeight;
  1079. }
  1080. if (typeof element === "string") {
  1081. element = document.querySelector(element);
  1082. }
  1083. if (element == void 0) {
  1084. return;
  1085. }
  1086. if (element.nodeType === 9) {
  1087. /* 文档节点 */
  1088. return Math.max(
  1089. element.body.scrollHeight,
  1090. element.documentElement.scrollHeight,
  1091. element.body.offsetHeight,
  1092. element.documentElement.offsetHeight,
  1093. element.documentElement.clientHeight
  1094. );
  1095. }
  1096. let handleElement = CommonUtils.showElement(element);
  1097. let view = element.ownerDocument.defaultView;
  1098. if (!view || !view.opener) {
  1099. view = window;
  1100. }
  1101. let styles = view.getComputedStyle(element);
  1102. let elementPaddingTop = parseFloat(styles.paddingTop);
  1103. let elementPaddingBottom = parseFloat(styles.paddingBottom);
  1104. if (isNaN(elementPaddingTop)) {
  1105. elementPaddingTop = 0;
  1106. }
  1107. if (isNaN(elementPaddingBottom)) {
  1108. elementPaddingBottom = 0;
  1109. }
  1110. let elementHeight =
  1111. element.clientHeight - elementPaddingTop - elementPaddingBottom;
  1112. handleElement.recovery();
  1113. return elementHeight;
  1114. };
  1115. /**
  1116. * 获取元素的外部宽度(包括边框和外边距)
  1117. * @param {HTMLElement|string} element 要获取外部宽度的元素
  1118. * @returns {number} 元素的外部宽度,单位为像素
  1119. * @example
  1120. * // 获取元素a.xx的外部宽度
  1121. * DOMUtils.outerWidth(document.querySelector("a.xx"))
  1122. * DOMUtils.outerWidth("a.xx")
  1123. * > 100
  1124. * // 获取window的外部宽度
  1125. * DOMUtils.outerWidth(window)
  1126. * > 400
  1127. */
  1128. DOMUtils.outerWidth = function (element) {
  1129. if (CommonUtils.isWin(element)) {
  1130. return window.innerWidth;
  1131. }
  1132. if (typeof element === "string") {
  1133. element = document.querySelector(element);
  1134. }
  1135. if (element == void 0) {
  1136. return;
  1137. }
  1138. let handleElement = CommonUtils.showElement(element);
  1139. let style = getComputedStyle(element, null);
  1140. let elementMarginLeft = parseFloat(style.marginLeft);
  1141. let elementMarginRight = parseFloat(style.marginRight);
  1142. if (isNaN(elementMarginLeft)) {
  1143. elementMarginLeft = 0;
  1144. }
  1145. if (isNaN(elementMarginRight)) {
  1146. elementMarginRight = 0;
  1147. }
  1148. handleElement.recovery();
  1149. return element.offsetWidth + elementMarginLeft + elementMarginRight;
  1150. };
  1151. /**
  1152. * 获取元素的外部高度(包括边框和外边距)
  1153. * @param {HTMLElement|string} element 要获取外部高度的元素
  1154. * @returns {number} 元素的外部高度,单位为像素
  1155. * @example
  1156. * // 获取元素a.xx的外部高度
  1157. * DOMUtils.outerHeight(document.querySelector("a.xx"))
  1158. * DOMUtils.outerHeight("a.xx")
  1159. * > 100
  1160. * // 获取window的外部高度
  1161. * DOMUtils.outerHeight(window)
  1162. * > 700
  1163. */
  1164. DOMUtils.outerHeight = function (element) {
  1165. if (CommonUtils.isWin(element)) {
  1166. return window.innerHeight;
  1167. }
  1168. if (typeof element === "string") {
  1169. element = document.querySelector(element);
  1170. }
  1171. if (element == void 0) {
  1172. return;
  1173. }
  1174. let handleElement = CommonUtils.showElement(element);
  1175. let style = getComputedStyle(element, null);
  1176. let elementMarginTop = parseFloat(style.marginTop);
  1177. let elementMarginBottom = parseFloat(style.marginBottom);
  1178. if (isNaN(elementMarginTop)) {
  1179. elementMarginTop = 0;
  1180. }
  1181. if (isNaN(elementMarginBottom)) {
  1182. elementMarginBottom = 0;
  1183. }
  1184. handleElement.recovery();
  1185. return element.offsetHeight + elementMarginTop + elementMarginBottom;
  1186. };
  1187.  
  1188. /**
  1189. * 等待文档加载完成后执行指定的函数
  1190. * @param {Function} callback 需要执行的函数
  1191. * @example
  1192. * DOMUtils.ready(function(){
  1193. * console.log("文档加载完毕")
  1194. * })
  1195. */
  1196. DOMUtils.ready = function (callback) {
  1197. function completed() {
  1198. document.removeEventListener("DOMContentLoaded", completed);
  1199. window.removeEventListener("load", completed);
  1200. callback();
  1201. }
  1202. if (
  1203. document.readyState === "complete" ||
  1204. (document.readyState !== "loading" && !document.documentElement.doScroll)
  1205. ) {
  1206. window.setTimeout(callback);
  1207. } else {
  1208. /* 监听DOMContentLoaded事件 */
  1209. document.addEventListener("DOMContentLoaded", completed);
  1210. /* 监听load事件 */
  1211. window.addEventListener("load", completed);
  1212. }
  1213. };
  1214.  
  1215. /**
  1216. * 在一定时间内改变元素的样式属性,实现动画效果
  1217. * @param {HTMLElement|string} element 需要进行动画的元素
  1218. * @param {CSSStyleDeclaration} styles 动画结束时元素的样式属性
  1219. * @param {number} [duration=1000] 动画持续时间,单位为毫秒
  1220. * @param {Function} [callback=null] 动画结束后执行的函数
  1221. * @example
  1222. * // 监听元素a.xx的从显示变为隐藏
  1223. * DOMUtils.animate(document.querySelector("a.xx"),{ top:100},1000,function(){
  1224. * console.log("已往上位移100px")
  1225. * })
  1226. */
  1227. DOMUtils.animate = function (
  1228. element,
  1229. styles,
  1230. duration = 1000,
  1231. callback = null
  1232. ) {
  1233. if (typeof element === "string") {
  1234. element = document.querySelector(element);
  1235. }
  1236. if (element == void 0) {
  1237. return;
  1238. }
  1239. if (typeof duration !== "number" || duration <= 0) {
  1240. throw new TypeError("duration must be a positive number");
  1241. }
  1242. if (typeof callback !== "function" && callback !== void 0) {
  1243. throw new TypeError("callback must be a function or null");
  1244. }
  1245. if (typeof styles !== "object" || styles === void 0) {
  1246. throw new TypeError("styles must be an object");
  1247. }
  1248. if (Object.keys(styles).length === 0) {
  1249. throw new Error("styles must contain at least one property");
  1250. }
  1251. let start = performance.now();
  1252. let from = {};
  1253. let to = {};
  1254. for (let prop in styles) {
  1255. from[prop] = element.style[prop] || getComputedStyle(element)[prop];
  1256. to[prop] = styles[prop];
  1257. }
  1258. let timer = setInterval(function () {
  1259. let timePassed = performance.now() - start;
  1260. let progress = timePassed / duration;
  1261. if (progress > 1) {
  1262. progress = 1;
  1263. }
  1264. for (let prop in styles) {
  1265. element.style[prop] =
  1266. from[prop] + (to[prop] - from[prop]) * progress + "px";
  1267. }
  1268. if (progress === 1) {
  1269. clearInterval(timer);
  1270. if (callback) {
  1271. callback();
  1272. }
  1273. }
  1274. }, 10);
  1275. };
  1276.  
  1277. /**
  1278. * 将一个元素包裹在指定的HTML元素中
  1279. * @param {HTMLElement|string} element 要包裹的元素
  1280. * @param {string} wrapperHTML 要包裹的HTML元素的字符串表示形式
  1281. * @example
  1282. * // 将a.xx元素外面包裹一层div
  1283. * DOMUtils.wrap(document.querySelector("a.xx"),"<div></div>")
  1284. */
  1285. DOMUtils.wrap = function (element, wrapperHTML) {
  1286. if (typeof element === "string") {
  1287. element = document.querySelector(element);
  1288. }
  1289. if (element == void 0) {
  1290. return;
  1291. }
  1292. // 创建一个新的div元素,并将wrapperHTML作为其innerHTML
  1293. let wrapper = document.createElement("div");
  1294. wrapper.innerHTML = wrapperHTML;
  1295.  
  1296. wrapper = wrapper.firstChild;
  1297. // 将要包裹的元素插入目标元素前面
  1298. element.parentElement.insertBefore(wrapper, element);
  1299.  
  1300. // 将要包裹的元素移动到wrapper中
  1301. wrapper.appendChild(element);
  1302. };
  1303. /**
  1304. * 获取当前元素的前一个兄弟元素
  1305. * @param {HTMLElement|string} element 当前元素
  1306. * @returns {?HTMLElement} 前一个兄弟元素
  1307. * @example
  1308. * // 获取a.xx元素前一个兄弟元素
  1309. * DOMUtils.prev(document.querySelector("a.xx"))
  1310. * DOMUtils.prev("a.xx")
  1311. * > <div ...>....</div>
  1312. */
  1313. DOMUtils.prev = function (element) {
  1314. if (typeof element === "string") {
  1315. element = document.querySelector(element);
  1316. }
  1317. if (element == void 0) {
  1318. return;
  1319. }
  1320. return element.previousElementSibling;
  1321. };
  1322.  
  1323. /**
  1324. * 获取当前元素的后一个兄弟元素
  1325. * @param {HTMLElement|string} element 当前元素
  1326. * @returns {?HTMLElement} 后一个兄弟元素
  1327. * @example
  1328. * // 获取a.xx元素前一个兄弟元素
  1329. * DOMUtils.next(document.querySelector("a.xx"))
  1330. * DOMUtils.next("a.xx")
  1331. * > <div ...>....</div>
  1332. */
  1333. DOMUtils.next = function (element) {
  1334. if (typeof element === "string") {
  1335. element = document.querySelector(element);
  1336. }
  1337. if (element == void 0) {
  1338. return;
  1339. }
  1340. return element.nextElementSibling;
  1341. };
  1342.  
  1343. /**
  1344. * 释放原有的DOMUtils控制权
  1345. * @example
  1346. * let DOMUtils = window.DOMUtils.noConflict()
  1347. */
  1348. DOMUtils.noConflict = function () {
  1349. if (window.DOMUtils) {
  1350. delete window.DOMUtils;
  1351. }
  1352. if (AnotherDOMUtils) {
  1353. window.DOMUtils = AnotherDOMUtils;
  1354. }
  1355. return DOMUtils;
  1356. };
  1357.  
  1358. /**
  1359. * 获取当前元素的所有兄弟元素
  1360. * @param {HTMLElement|string} element 当前元素
  1361. * @returns {HTMLElement[]} 所有兄弟元素
  1362. * @example
  1363. * // 获取a.xx元素所有兄弟元素
  1364. * DOMUtils.siblings(document.querySelector("a.xx"))
  1365. * DOMUtils.siblings("a.xx")
  1366. * > (3) [div.logo-wrapper, div.forum-block, div.more-btn-desc]
  1367. */
  1368. DOMUtils.siblings = function (element) {
  1369. if (typeof element === "string") {
  1370. element = document.querySelector(element);
  1371. }
  1372. if (element == void 0) {
  1373. return;
  1374. }
  1375. return Array.from(element.parentElement.children).filter(
  1376. (child) => child !== element
  1377. );
  1378. };
  1379.  
  1380. /**
  1381. * 获取当前元素的父元素
  1382. * @param {HTMLElement|NodeList|string} element 当前元素
  1383. * @returns {?HTMLElement[]|HTMLElement} 父元素
  1384. * @example
  1385. * // 获取a.xx元素的父元素
  1386. * DOMUtils.parent(document.querySelector("a.xx"))
  1387. * DOMUtils.parent("a.xx")
  1388. * > <div ...>....</div>
  1389. */
  1390. DOMUtils.parent = function (element) {
  1391. if (typeof element === "string") {
  1392. element = document.querySelector(element);
  1393. }
  1394. if (element == void 0) {
  1395. return;
  1396. }
  1397. if (element instanceof NodeList || element instanceof Array) {
  1398. let resultArray = [];
  1399. element.forEach((item) => {
  1400. resultArray = resultArray.concat(this.parent(item));
  1401. });
  1402. return resultArray;
  1403. } else {
  1404. return element.parentElement;
  1405. }
  1406. };
  1407.  
  1408. /**
  1409. * 将字符串转为Element元素
  1410. * @param {string} html
  1411. * @param {boolean} useParser 是否使用DOMParser来生成元素,有些时候通过DOMParser生成的元素有点问题
  1412. * @param {boolean} isComplete 是否是完整的
  1413. * @returns {HTMLElement}
  1414. * @example
  1415. * // 将字符串转为Element元素
  1416. * DOMUtils.parseHTML("<a href='xxxx'></a>")
  1417. * > <a href="xxxx"></a>
  1418. * @example
  1419. * // 使用DOMParser将字符串转为Element元素
  1420. * DOMUtils.parseHTML("<a href='xxxx'></a>",true)
  1421. * > <a href="xxxx"></a>
  1422. * @example
  1423. * // 由于需要转换的元素是多个元素,将字符串转为完整的Element元素
  1424. * DOMUtils.parseHTML("<a href='xxxx'></a><a href='xxxx'></a>",false, true)
  1425. * > <div><a href="xxxx"></a><a href='xxxx'></a></div>
  1426. * @example
  1427. * // 由于需要转换的元素是多个元素,使用DOMParser将字符串转为完整的Element元素
  1428. * DOMUtils.parseHTML("<a href='xxxx'></a><a href='xxxx'></a>",true, true)
  1429. * > #document
  1430. */
  1431. DOMUtils.parseHTML = function (html, useParser = false, isComplete = false) {
  1432. function parseHTMLByDOMParser() {
  1433. let parser = new DOMParser();
  1434. if (isComplete) {
  1435. return parser.parseFromString(html, "text/html");
  1436. } else {
  1437. return parser.parseFromString(html, "text/html").body.firstChild;
  1438. }
  1439. }
  1440. function parseHTMLByCreateDom() {
  1441. let tempDIV = document.createElement("div");
  1442. tempDIV.innerHTML = html;
  1443. if (isComplete) {
  1444. return tempDIV;
  1445. } else {
  1446. return tempDIV.firstChild;
  1447. }
  1448. }
  1449. if (useParser) {
  1450. return parseHTMLByDOMParser();
  1451. } else {
  1452. return parseHTMLByCreateDom();
  1453. }
  1454. };
  1455.  
  1456. /**
  1457. * 当鼠标移入或移出元素时触发事件
  1458. * @param {HTMLElement|string} element 当前元素
  1459. * @param {(event:Event)=>{}} handler 事件处理函数
  1460. * @example
  1461. * // 监听a.xx元素的移入或移出
  1462. * DOMUtils.hover(document.querySelector("a.xx"),()=>{
  1463. * console.log("移入/移除");
  1464. * })
  1465. * DOMUtils.hover("a.xx",()=>{
  1466. * console.log("移入/移除");
  1467. * })
  1468. */
  1469. DOMUtils.hover = function (element, handler) {
  1470. if (typeof element === "string") {
  1471. element = document.querySelector(element);
  1472. }
  1473. if (element == void 0) {
  1474. return;
  1475. }
  1476. DOMUtils.on(element, "mouseenter", null, handler);
  1477. DOMUtils.on(element, "mouseleave", null, handler);
  1478. };
  1479.  
  1480. /**
  1481. * 显示元素
  1482. * @param {HTMLElement|string} element 当前元素
  1483. * @example
  1484. * // 显示a.xx元素
  1485. * DOMUtils.show(document.querySelector("a.xx"))
  1486. * DOMUtils.show("a.xx")
  1487. */
  1488. DOMUtils.show = function (element) {
  1489. if (typeof element === "string") {
  1490. element = document.querySelector(element);
  1491. }
  1492. if (element == void 0) {
  1493. return;
  1494. }
  1495. element.style.display = "";
  1496. };
  1497.  
  1498. /**
  1499. * 隐藏元素
  1500. * @param {HTMLElement|string} element 当前元素
  1501. * @example
  1502. * // 隐藏a.xx元素
  1503. * DOMUtils.hide(document.querySelector("a.xx"))
  1504. * DOMUtils.hide("a.xx")
  1505. */
  1506. DOMUtils.hide = function (element) {
  1507. if (typeof element === "string") {
  1508. element = document.querySelector(element);
  1509. }
  1510. if (element == void 0) {
  1511. return;
  1512. }
  1513. element.style.display = "none";
  1514. };
  1515.  
  1516. /**
  1517. * 当按键松开时触发事件
  1518. * @param {HTMLElement|string} element 当前元素
  1519. * @param {Function} handler 事件处理函数
  1520. * @example
  1521. * // 监听a.xx元素的按键松开
  1522. * DOMUtils.keyup(document.querySelector("a.xx"),()=>{
  1523. * console.log("按键松开");
  1524. * })
  1525. * DOMUtils.keyup("a.xx",()=>{
  1526. * console.log("按键松开");
  1527. * })
  1528. */
  1529. DOMUtils.keyup = function (element, handler) {
  1530. if (typeof element === "string") {
  1531. element = document.querySelector(element);
  1532. }
  1533. if (element == void 0) {
  1534. return;
  1535. }
  1536. DOMUtils.on(element, "keyup", null, handler);
  1537. };
  1538.  
  1539. /**
  1540. * 当按键按下时触发事件
  1541. * @param {HTMLElement|string} element 当前元素
  1542. * @param {Function} handler 事件处理函数
  1543. * @example
  1544. * // 监听a.xx元素的按键按下
  1545. * DOMUtils.keydown(document.querySelector("a.xx"),()=>{
  1546. * console.log("按键按下");
  1547. * })
  1548. * DOMUtils.keydown("a.xx",()=>{
  1549. * console.log("按键按下");
  1550. * })
  1551. */
  1552. DOMUtils.keydown = function (element, handler) {
  1553. if (typeof element === "string") {
  1554. element = document.querySelector(element);
  1555. }
  1556. if (element == void 0) {
  1557. return;
  1558. }
  1559. DOMUtils.on(element, "keydown", null, handler);
  1560. };
  1561.  
  1562. /**
  1563. * 淡入元素
  1564. * @param {HTMLElement|string} element 当前元素
  1565. * @param {number} [duration=400] 动画持续时间(毫秒),默认400毫秒
  1566. * @param {Function} callback 动画结束的回调
  1567. * @example
  1568. * // 元素a.xx淡入
  1569. * DOMUtils.fadeIn(document.querySelector("a.xx"),2500,()=>{
  1570. * console.log("淡入完毕");
  1571. * })
  1572. * DOMUtils.fadeIn("a.xx",undefined,()=>{
  1573. * console.log("淡入完毕");
  1574. * })
  1575. */
  1576. DOMUtils.fadeIn = function (element, duration = 400, callback) {
  1577. if (typeof element === "string") {
  1578. element = document.querySelector(element);
  1579. }
  1580. if (element == void 0) {
  1581. return;
  1582. }
  1583. element.style.opacity = 0;
  1584. element.style.display = "";
  1585. let start = null;
  1586. let timer = null;
  1587. function step(timestamp) {
  1588. if (!start) start = timestamp;
  1589. let progress = timestamp - start;
  1590. element.style.opacity = Math.min(progress / duration, 1);
  1591. if (progress < duration) {
  1592. window.requestAnimationFrame(step);
  1593. } else {
  1594. if (callback && typeof callback === "function") {
  1595. callback();
  1596. }
  1597. window.cancelAnimationFrame(timer);
  1598. }
  1599. }
  1600. timer = window.requestAnimationFrame(step);
  1601. };
  1602.  
  1603. /**
  1604. * 淡出元素
  1605. * @param {HTMLElement|string} element 当前元素
  1606. * @param {number} [duration=400] 动画持续时间(毫秒),默认400毫秒
  1607. * @param {Function} callback 动画结束的回调
  1608. * @example
  1609. * // 元素a.xx淡出
  1610. * DOMUtils.fadeOut(document.querySelector("a.xx"),2500,()=>{
  1611. * console.log("淡出完毕");
  1612. * })
  1613. * DOMUtils.fadeOut("a.xx",undefined,()=>{
  1614. * console.log("淡出完毕");
  1615. * })
  1616. */
  1617. DOMUtils.fadeOut = function (element, duration = 400, callback) {
  1618. if (typeof element === "string") {
  1619. element = document.querySelector(element);
  1620. }
  1621. if (element == void 0) {
  1622. return;
  1623. }
  1624. element.style.opacity = 1;
  1625. let start = null;
  1626. let timer = null;
  1627. function step(timestamp) {
  1628. if (!start) start = timestamp;
  1629. let progress = timestamp - start;
  1630. element.style.opacity = Math.max(1 - progress / duration, 0);
  1631. if (progress < duration) {
  1632. window.requestAnimationFrame(step);
  1633. } else {
  1634. element.style.display = "none";
  1635. if (typeof callback === "function") {
  1636. callback();
  1637. }
  1638. window.cancelAnimationFrame(timer);
  1639. }
  1640. }
  1641. timer = window.requestAnimationFrame(step);
  1642. };
  1643.  
  1644. /**
  1645. * 切换元素的显示和隐藏状态
  1646. * @param {HTMLElement|string} element 当前元素
  1647. * @example
  1648. * // 如果元素a.xx当前是隐藏,则显示,如果是显示,则隐藏
  1649. * DOMUtils.toggle(document.querySelector("a.xx"))
  1650. * DOMUtils.toggle("a.xx")
  1651. */
  1652. DOMUtils.toggle = function (element) {
  1653. if (typeof element === "string") {
  1654. element = document.querySelector(element);
  1655. }
  1656. if (element == void 0) {
  1657. return;
  1658. }
  1659. if (getComputedStyle(element).getPropertyValue("display") === "none") {
  1660. DOMUtils.show(element);
  1661. } else {
  1662. DOMUtils.hide(element);
  1663. }
  1664. };
  1665. return DOMUtils;
  1666. });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址