DOMUtils

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

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

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/465772/1296230/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|undefined} capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
  703. * @param {boolean|undefined} once 表示事件是否只触发一次。默认为false
  704. * @param {boolean|undefined} passive 表示事件监听器是否不会调用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,
  733. once,
  734. passive
  735. ) {
  736. if (typeof element === "string") {
  737. element = document.querySelectorAll(element);
  738. }
  739. if (element == void 0) {
  740. return;
  741. }
  742. /**
  743. * @type {HTMLElement[]}
  744. */
  745. let elementList = [];
  746. if (element instanceof NodeList || Array.isArray(element)) {
  747. elementList = elementList.concat(element);
  748. } else {
  749. elementList.push(element);
  750. }
  751. /**
  752. * @type {string[]}
  753. */
  754. let eventTypeList = [];
  755. if (Array.isArray(eventType)) {
  756. eventTypeList = eventTypeList.concat(eventType);
  757. } else if (typeof eventType === "string") {
  758. eventTypeList = eventTypeList.concat(eventType.split(" "));
  759. }
  760. /**
  761. * 元素属性上自定义的用于暂存事件的对象名
  762. */
  763. let propEventsName = "events";
  764. /**
  765. * window属性上自定义的用于暂存事件的对象名
  766. */
  767. let windowEventsName = "DOMUtilsGlobalEvents";
  768. /**
  769. * @type {?string}
  770. */
  771. let _selector_ = selector;
  772. /**
  773. * @type {(event:Event)=>{}}
  774. */
  775. let _callback_ = callback;
  776. if (typeof selector === "function") {
  777. /* 这是为没有selector的情况 */
  778. _selector_ = void 0;
  779. _callback_ = selector;
  780. }
  781. elementList.forEach((elementItem) => {
  782. let ownCallBack = function (event) {
  783. let target = event.target;
  784. if (_selector_) {
  785. /* 存在自定义子元素选择器 */
  786. let totalParent = CommonUtils.isWin(elementItem)
  787. ? document.documentElement
  788. : elementItem;
  789. if (target.matches(_selector_)) {
  790. /* 当前目标可以被selector所匹配到 */
  791. _callback_.call(target, event);
  792. return;
  793. } else if (
  794. target.closest(_selector_) &&
  795. totalParent.contains(target.closest(_selector_))
  796. ) {
  797. /* 在上层与主元素之间寻找可以被selector所匹配到的 */
  798. let closestElement = target.closest(_selector_);
  799. /* event的target值不能直接修改 */
  800. Object.defineProperty(event, "target", {
  801. get() {
  802. return closestElement;
  803. },
  804. });
  805. _callback_.call(closestElement, event);
  806. return;
  807. }
  808. } else {
  809. _callback_.call(elementItem, event);
  810. }
  811. };
  812. /* 遍历事件名设置元素事件 */
  813. eventTypeList.forEach((eventName) => {
  814. elementItem.addEventListener(
  815. eventName,
  816. ownCallBack,
  817. capture,
  818. once,
  819. passive
  820. );
  821. });
  822.  
  823. if (_callback_ && _callback_.delegate) {
  824. elementItem.setAttribute("data-delegate", _selector_);
  825. }
  826. if (CommonUtils.isWin(elementItem)) {
  827. let elementEvents = elementItem[windowEventsName] || {};
  828. elementEvents[eventType] = elementEvents[eventType] || [];
  829. elementEvents[eventType].push({
  830. selector: _selector_,
  831. callback: ownCallBack,
  832. originCallBack: _callback_,
  833. });
  834. elementItem[windowEventsName] = elementEvents;
  835. } else {
  836. let elementEvents = elementItem[propEventsName] || {};
  837. elementEvents[eventType] = elementEvents[eventType] || [];
  838. elementEvents[eventType].push({
  839. selector: _selector_,
  840. callback: ownCallBack,
  841. originCallBack: _callback_,
  842. });
  843. elementItem[propEventsName] = elementEvents;
  844. }
  845. });
  846. };
  847. /**
  848. * 取消绑定事件
  849. * @param {HTMLElement|string|NodeList|Array|Window} element 需要取消绑定的元素|元素数组
  850. * @param {string|[...string]} eventType 需要取消监听的事件
  851. * @param {string|undefined} selector 子元素选择器
  852. * @param {Function|undefined} callback 通过DOMUtils.on绑定的事件函数
  853. * @param {boolean|undefined} [useCapture] 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
  854. * @example
  855. * // 取消监听元素a.xx的click事件
  856. * DOMUtils.off(document.querySelector("a.xx"),"click")
  857. * DOMUtils.off("a.xx","click")
  858. * // 取消监听元素a.xx的click、tap、hover事件
  859. * DOMUtils.off(document.querySelector("a.xx"),"click tap hover")
  860. * DOMUtils.off("a.xx",["click","tap","hover"])
  861. * // 取消监听全局下的a.xx的点击事件
  862. * DOMUtils.off(document,"click","a.xx")
  863. */
  864. DOMUtils.off = function (element, eventType, selector, callback, useCapture) {
  865. if (typeof element === "string") {
  866. element = document.querySelectorAll(element);
  867. }
  868. if (element == void 0) {
  869. return;
  870. }
  871. /**
  872. * @type {HTMLElement[]}
  873. */
  874. let elementList = [];
  875. if (element instanceof NodeList || Array.isArray(element)) {
  876. elementList = elementList.concat(element);
  877. } else {
  878. elementList.push(element);
  879. }
  880. /**
  881. * @type {string[]}
  882. */
  883. let eventTypeList = [];
  884. if (Array.isArray(eventType)) {
  885. eventTypeList = eventTypeList.concat(eventType);
  886. } else if (typeof eventType === "string") {
  887. eventTypeList = eventTypeList.concat(eventType.split(" "));
  888. }
  889. /**
  890. * 元素属性上自定义的用于暂存事件的对象名
  891. */
  892. let propEventsName = "events";
  893. /**
  894. * window属性上自定义的用于暂存事件的对象名
  895. */
  896. let windowEventsName = "DOMUtilsGlobalEvents";
  897. /**
  898. * @type {?string}
  899. */
  900. let _selector_ = selector;
  901. /**
  902. * @type {(event:Event)=>{}}
  903. */
  904. let _callback_ = callback;
  905. if (typeof selector === "function") {
  906. /* 这是为没有selector的情况 */
  907. _selector_ = void 0;
  908. _callback_ = selector;
  909. }
  910. elementList.forEach((elementItem) => {
  911. let elementEvents = {};
  912. if (CommonUtils.isWin(elementItem)) {
  913. elementEvents = elementItem[windowEventsName] || {};
  914. } else {
  915. elementEvents = elementItem[propEventsName] || {};
  916. }
  917. eventTypeList.forEach((eventName) => {
  918. let handlers = elementEvents[eventName] || [];
  919. for (let index = 0; index < handlers.length; index++) {
  920. if (
  921. (!_selector_ || handlers[index].selector === _selector_) &&
  922. (!_callback_ ||
  923. handlers[index].callback === _callback_ ||
  924. handlers[index].originCallBack === _callback_)
  925. ) {
  926. elementItem.removeEventListener(
  927. eventName,
  928. handlers[index].callback,
  929. useCapture
  930. );
  931. handlers.splice(index--, 1);
  932. }
  933. }
  934. if (handlers.length === 0) {
  935. delete elementEvents[eventType];
  936. }
  937. });
  938. if (CommonUtils.isWin(elementItem)) {
  939. elementItem[windowEventsName] = elementEvents;
  940. } else {
  941. elementItem[propEventsName] = elementEvents;
  942. }
  943. });
  944. };
  945.  
  946. /**
  947. * 主动触发事件
  948. * @param {HTMLElement|string|NodeList|Array|Window} element 需要触发的元素|元素数组|window
  949. * @param {string|[...string]} eventType 需要触发的事件
  950. * @param {object|undefined} details 赋予触发的Event的额外属性
  951. * @param {boolean} [useDispatchToTriggerEvent=true] 是否使用dispatchEvent来触发事件,默认true
  952. * @example
  953. * // 触发元素a.xx的click事件
  954. * DOMUtils.trigger(document.querySelector("a.xx"),"click")
  955. * DOMUtils.trigger("a.xx","click")
  956. * // 触发元素a.xx的click、tap、hover事件
  957. * DOMUtils.trigger(document.querySelector("a.xx"),"click tap hover")
  958. * DOMUtils.trigger("a.xx",["click","tap","hover"])
  959. */
  960. DOMUtils.trigger = function (
  961. element,
  962. eventType,
  963. details,
  964. useDispatchToTriggerEvent = true
  965. ) {
  966. if (typeof element === "string") {
  967. element = document.querySelector(element);
  968. }
  969. if (element == void 0) {
  970. return;
  971. }
  972. let elementList = [];
  973. if (element instanceof NodeList || Array.isArray(element)) {
  974. elementList = [...element];
  975. } else {
  976. elementList = [element];
  977. }
  978. let eventTypeList = [];
  979. if (!eventType) {
  980. for (let type in events) {
  981. eventTypeList = [...eventTypeList, type];
  982. }
  983. } else if (Array.isArray(eventType)) {
  984. eventTypeList = eventType;
  985. } else if (typeof eventType === "string") {
  986. eventTypeList = eventType.split(" ");
  987. }
  988.  
  989. elementList.forEach((elementItem) => {
  990. let events = {};
  991. if (CommonUtils.isWin(elementItem)) {
  992. events = elementItem["DOMUtilsGlobalEvents"] || {};
  993. } else {
  994. events = elementItem.events || {};
  995. }
  996. eventTypeList.forEach((_eventType_) => {
  997. let event = new Event(_eventType_);
  998. if (details) {
  999. Object.assign(event, details);
  1000. }
  1001. if (useDispatchToTriggerEvent == false && _eventType_ in events) {
  1002. events[_eventType_].forEach((eventsItem) => {
  1003. eventsItem.callback(event);
  1004. });
  1005. } else {
  1006. elementItem.dispatchEvent(event);
  1007. }
  1008. });
  1009. });
  1010. };
  1011. /**
  1012. * 设置或返回被选元素相对于文档的偏移坐标
  1013. * @param {HTMLElement|string} element
  1014. * @returns { {
  1015. * top: number,
  1016. * left: number
  1017. * }}
  1018. * @example
  1019. * // 获取元素a.xx的对于文档的偏移坐标
  1020. * DOMUtils.offset(document.querySelector("a.xx"))
  1021. * DOMUtils.offset("a.xx")
  1022. * > 0
  1023. */
  1024. DOMUtils.offset = function (element) {
  1025. if (typeof element === "string") {
  1026. element = document.querySelector(element);
  1027. }
  1028. if (element == void 0) {
  1029. return;
  1030. }
  1031. let rect = element.getBoundingClientRect();
  1032. let win = window;
  1033. return {
  1034. top: rect.top + win.scrollY,
  1035. left: rect.left + win.scrollX,
  1036. };
  1037. };
  1038. /**
  1039. * 获取元素的宽度
  1040. * @param {HTMLElement|string} element 要获取宽度的元素
  1041. * @returns {number} 元素的宽度,单位为像素
  1042. * @example
  1043. * // 获取元素a.xx的宽度
  1044. * DOMUtils.width(document.querySelector("a.xx"))
  1045. * DOMUtils.width("a.xx")
  1046. * > 100
  1047. * // 获取window的宽度
  1048. * DOMUtils.width(window)
  1049. * > 400
  1050. * @example
  1051. * // 设置元素a.xx的宽度为200
  1052. * DOMUtils.width(document.querySelector("a.xx"),200)
  1053. * DOMUtils.width("a.xx",200)
  1054. */
  1055. DOMUtils.width = function (element) {
  1056. if (CommonUtils.isWin(element)) {
  1057. return window.document.documentElement.clientWidth;
  1058. }
  1059. if (typeof element === "string") {
  1060. element = document.querySelector(element);
  1061. }
  1062. if (element == void 0) {
  1063. return;
  1064. }
  1065. if (element.nodeType === 9) {
  1066. /* 文档节点 */
  1067. return Math.max(
  1068. element.body.scrollWidth,
  1069. element.documentElement.scrollWidth,
  1070. element.body.offsetWidth,
  1071. element.documentElement.offsetWidth,
  1072. element.documentElement.clientWidth
  1073. );
  1074. }
  1075. let handleElement = CommonUtils.showElement(element);
  1076. let view = element.ownerDocument.defaultView;
  1077. if (!view || !view.opener) {
  1078. view = window;
  1079. }
  1080. let styles = view.getComputedStyle(element);
  1081. let elementPaddingLeft = parseFloat(styles.paddingLeft);
  1082. let elementPaddingRight = parseFloat(styles.paddingRight);
  1083. if (isNaN(elementPaddingLeft)) {
  1084. elementPaddingLeft = 0;
  1085. }
  1086. if (isNaN(elementPaddingRight)) {
  1087. elementPaddingRight = 0;
  1088. }
  1089. let elementWidth =
  1090. element.clientWidth - elementPaddingLeft - elementPaddingRight;
  1091. handleElement.recovery();
  1092. return elementWidth;
  1093. };
  1094. /**
  1095. * 获取元素的高度
  1096. * @param {HTMLElement|string} element 要获取高度的元素
  1097. * @returns {number} 元素的高度,单位为像素
  1098. * @example
  1099. * // 获取元素a.xx的高度
  1100. * DOMUtils.height(document.querySelector("a.xx"))
  1101. * DOMUtils.height("a.xx")
  1102. * > 100
  1103. * // 获取window的高度
  1104. * DOMUtils.height(window)
  1105. * > 700
  1106. * @example
  1107. * // 设置元素a.xx的高度为200
  1108. * DOMUtils.height(document.querySelector("a.xx"),200)
  1109. * DOMUtils.height("a.xx",200)
  1110. */
  1111. DOMUtils.height = function (element) {
  1112. if (CommonUtils.isWin(element)) {
  1113. return window.document.documentElement.clientHeight;
  1114. }
  1115. if (typeof element === "string") {
  1116. element = document.querySelector(element);
  1117. }
  1118. if (element == void 0) {
  1119. return;
  1120. }
  1121. if (element.nodeType === 9) {
  1122. /* 文档节点 */
  1123. return Math.max(
  1124. element.body.scrollHeight,
  1125. element.documentElement.scrollHeight,
  1126. element.body.offsetHeight,
  1127. element.documentElement.offsetHeight,
  1128. element.documentElement.clientHeight
  1129. );
  1130. }
  1131. let handleElement = CommonUtils.showElement(element);
  1132. let view = element.ownerDocument.defaultView;
  1133. if (!view || !view.opener) {
  1134. view = window;
  1135. }
  1136. let styles = view.getComputedStyle(element);
  1137. let elementPaddingTop = parseFloat(styles.paddingTop);
  1138. let elementPaddingBottom = parseFloat(styles.paddingBottom);
  1139. if (isNaN(elementPaddingTop)) {
  1140. elementPaddingTop = 0;
  1141. }
  1142. if (isNaN(elementPaddingBottom)) {
  1143. elementPaddingBottom = 0;
  1144. }
  1145. let elementHeight =
  1146. element.clientHeight - elementPaddingTop - elementPaddingBottom;
  1147. handleElement.recovery();
  1148. return elementHeight;
  1149. };
  1150. /**
  1151. * 获取元素的外部宽度(包括边框和外边距)
  1152. * @param {HTMLElement|string} element 要获取外部宽度的元素
  1153. * @returns {number} 元素的外部宽度,单位为像素
  1154. * @example
  1155. * // 获取元素a.xx的外部宽度
  1156. * DOMUtils.outerWidth(document.querySelector("a.xx"))
  1157. * DOMUtils.outerWidth("a.xx")
  1158. * > 100
  1159. * // 获取window的外部宽度
  1160. * DOMUtils.outerWidth(window)
  1161. * > 400
  1162. */
  1163. DOMUtils.outerWidth = function (element) {
  1164. if (CommonUtils.isWin(element)) {
  1165. return window.innerWidth;
  1166. }
  1167. if (typeof element === "string") {
  1168. element = document.querySelector(element);
  1169. }
  1170. if (element == void 0) {
  1171. return;
  1172. }
  1173. let handleElement = CommonUtils.showElement(element);
  1174. let style = getComputedStyle(element, null);
  1175. let elementMarginLeft = parseFloat(style.marginLeft);
  1176. let elementMarginRight = parseFloat(style.marginRight);
  1177. if (isNaN(elementMarginLeft)) {
  1178. elementMarginLeft = 0;
  1179. }
  1180. if (isNaN(elementMarginRight)) {
  1181. elementMarginRight = 0;
  1182. }
  1183. handleElement.recovery();
  1184. return element.offsetWidth + elementMarginLeft + elementMarginRight;
  1185. };
  1186. /**
  1187. * 获取元素的外部高度(包括边框和外边距)
  1188. * @param {HTMLElement|string} element 要获取外部高度的元素
  1189. * @returns {number} 元素的外部高度,单位为像素
  1190. * @example
  1191. * // 获取元素a.xx的外部高度
  1192. * DOMUtils.outerHeight(document.querySelector("a.xx"))
  1193. * DOMUtils.outerHeight("a.xx")
  1194. * > 100
  1195. * // 获取window的外部高度
  1196. * DOMUtils.outerHeight(window)
  1197. * > 700
  1198. */
  1199. DOMUtils.outerHeight = function (element) {
  1200. if (CommonUtils.isWin(element)) {
  1201. return window.innerHeight;
  1202. }
  1203. if (typeof element === "string") {
  1204. element = document.querySelector(element);
  1205. }
  1206. if (element == void 0) {
  1207. return;
  1208. }
  1209. let handleElement = CommonUtils.showElement(element);
  1210. let style = getComputedStyle(element, null);
  1211. let elementMarginTop = parseFloat(style.marginTop);
  1212. let elementMarginBottom = parseFloat(style.marginBottom);
  1213. if (isNaN(elementMarginTop)) {
  1214. elementMarginTop = 0;
  1215. }
  1216. if (isNaN(elementMarginBottom)) {
  1217. elementMarginBottom = 0;
  1218. }
  1219. handleElement.recovery();
  1220. return element.offsetHeight + elementMarginTop + elementMarginBottom;
  1221. };
  1222.  
  1223. /**
  1224. * 等待文档加载完成后执行指定的函数
  1225. * @param {Function} callback 需要执行的函数
  1226. * @example
  1227. * DOMUtils.ready(function(){
  1228. * console.log("文档加载完毕")
  1229. * })
  1230. */
  1231. DOMUtils.ready = function (callback) {
  1232. function completed() {
  1233. document.removeEventListener("DOMContentLoaded", completed);
  1234. window.removeEventListener("load", completed);
  1235. callback();
  1236. }
  1237. if (
  1238. document.readyState === "complete" ||
  1239. (document.readyState !== "loading" && !document.documentElement.doScroll)
  1240. ) {
  1241. window.setTimeout(callback);
  1242. } else {
  1243. /* 监听DOMContentLoaded事件 */
  1244. document.addEventListener("DOMContentLoaded", completed);
  1245. /* 监听load事件 */
  1246. window.addEventListener("load", completed);
  1247. }
  1248. };
  1249.  
  1250. /**
  1251. * 在一定时间内改变元素的样式属性,实现动画效果
  1252. * @param {HTMLElement|string} element 需要进行动画的元素
  1253. * @param {CSSStyleDeclaration} styles 动画结束时元素的样式属性
  1254. * @param {number} [duration=1000] 动画持续时间,单位为毫秒
  1255. * @param {Function} [callback=null] 动画结束后执行的函数
  1256. * @example
  1257. * // 监听元素a.xx的从显示变为隐藏
  1258. * DOMUtils.animate(document.querySelector("a.xx"),{ top:100},1000,function(){
  1259. * console.log("已往上位移100px")
  1260. * })
  1261. */
  1262. DOMUtils.animate = function (
  1263. element,
  1264. styles,
  1265. duration = 1000,
  1266. callback = null
  1267. ) {
  1268. if (typeof element === "string") {
  1269. element = document.querySelector(element);
  1270. }
  1271. if (element == void 0) {
  1272. return;
  1273. }
  1274. if (typeof duration !== "number" || duration <= 0) {
  1275. throw new TypeError("duration must be a positive number");
  1276. }
  1277. if (typeof callback !== "function" && callback !== void 0) {
  1278. throw new TypeError("callback must be a function or null");
  1279. }
  1280. if (typeof styles !== "object" || styles === void 0) {
  1281. throw new TypeError("styles must be an object");
  1282. }
  1283. if (Object.keys(styles).length === 0) {
  1284. throw new Error("styles must contain at least one property");
  1285. }
  1286. let start = performance.now();
  1287. let from = {};
  1288. let to = {};
  1289. for (let prop in styles) {
  1290. from[prop] = element.style[prop] || getComputedStyle(element)[prop];
  1291. to[prop] = styles[prop];
  1292. }
  1293. let timer = setInterval(function () {
  1294. let timePassed = performance.now() - start;
  1295. let progress = timePassed / duration;
  1296. if (progress > 1) {
  1297. progress = 1;
  1298. }
  1299. for (let prop in styles) {
  1300. element.style[prop] =
  1301. from[prop] + (to[prop] - from[prop]) * progress + "px";
  1302. }
  1303. if (progress === 1) {
  1304. clearInterval(timer);
  1305. if (callback) {
  1306. callback();
  1307. }
  1308. }
  1309. }, 10);
  1310. };
  1311.  
  1312. /**
  1313. * 将一个元素包裹在指定的HTML元素中
  1314. * @param {HTMLElement|string} element 要包裹的元素
  1315. * @param {string} wrapperHTML 要包裹的HTML元素的字符串表示形式
  1316. * @example
  1317. * // 将a.xx元素外面包裹一层div
  1318. * DOMUtils.wrap(document.querySelector("a.xx"),"<div></div>")
  1319. */
  1320. DOMUtils.wrap = function (element, wrapperHTML) {
  1321. if (typeof element === "string") {
  1322. element = document.querySelector(element);
  1323. }
  1324. if (element == void 0) {
  1325. return;
  1326. }
  1327. // 创建一个新的div元素,并将wrapperHTML作为其innerHTML
  1328. let wrapper = document.createElement("div");
  1329. wrapper.innerHTML = wrapperHTML;
  1330.  
  1331. wrapper = wrapper.firstChild;
  1332. // 将要包裹的元素插入目标元素前面
  1333. element.parentElement.insertBefore(wrapper, element);
  1334.  
  1335. // 将要包裹的元素移动到wrapper中
  1336. wrapper.appendChild(element);
  1337. };
  1338. /**
  1339. * 获取当前元素的前一个兄弟元素
  1340. * @param {HTMLElement|string} element 当前元素
  1341. * @returns {?HTMLElement} 前一个兄弟元素
  1342. * @example
  1343. * // 获取a.xx元素前一个兄弟元素
  1344. * DOMUtils.prev(document.querySelector("a.xx"))
  1345. * DOMUtils.prev("a.xx")
  1346. * > <div ...>....</div>
  1347. */
  1348. DOMUtils.prev = function (element) {
  1349. if (typeof element === "string") {
  1350. element = document.querySelector(element);
  1351. }
  1352. if (element == void 0) {
  1353. return;
  1354. }
  1355. return element.previousElementSibling;
  1356. };
  1357.  
  1358. /**
  1359. * 获取当前元素的后一个兄弟元素
  1360. * @param {HTMLElement|string} element 当前元素
  1361. * @returns {?HTMLElement} 后一个兄弟元素
  1362. * @example
  1363. * // 获取a.xx元素前一个兄弟元素
  1364. * DOMUtils.next(document.querySelector("a.xx"))
  1365. * DOMUtils.next("a.xx")
  1366. * > <div ...>....</div>
  1367. */
  1368. DOMUtils.next = function (element) {
  1369. if (typeof element === "string") {
  1370. element = document.querySelector(element);
  1371. }
  1372. if (element == void 0) {
  1373. return;
  1374. }
  1375. return element.nextElementSibling;
  1376. };
  1377.  
  1378. /**
  1379. * 释放原有的DOMUtils控制权
  1380. * @example
  1381. * let DOMUtils = window.DOMUtils.noConflict()
  1382. */
  1383. DOMUtils.noConflict = function () {
  1384. if (window.DOMUtils) {
  1385. delete window.DOMUtils;
  1386. }
  1387. if (AnotherDOMUtils) {
  1388. window.DOMUtils = AnotherDOMUtils;
  1389. }
  1390. return DOMUtils;
  1391. };
  1392.  
  1393. /**
  1394. * 获取当前元素的所有兄弟元素
  1395. * @param {HTMLElement|string} element 当前元素
  1396. * @returns {HTMLElement[]} 所有兄弟元素
  1397. * @example
  1398. * // 获取a.xx元素所有兄弟元素
  1399. * DOMUtils.siblings(document.querySelector("a.xx"))
  1400. * DOMUtils.siblings("a.xx")
  1401. * > (3) [div.logo-wrapper, div.forum-block, div.more-btn-desc]
  1402. */
  1403. DOMUtils.siblings = function (element) {
  1404. if (typeof element === "string") {
  1405. element = document.querySelector(element);
  1406. }
  1407. if (element == void 0) {
  1408. return;
  1409. }
  1410. return Array.from(element.parentElement.children).filter(
  1411. (child) => child !== element
  1412. );
  1413. };
  1414.  
  1415. /**
  1416. * 获取当前元素的父元素
  1417. * @param {HTMLElement|NodeList|string} element 当前元素
  1418. * @returns {?HTMLElement[]|HTMLElement} 父元素
  1419. * @example
  1420. * // 获取a.xx元素的父元素
  1421. * DOMUtils.parent(document.querySelector("a.xx"))
  1422. * DOMUtils.parent("a.xx")
  1423. * > <div ...>....</div>
  1424. */
  1425. DOMUtils.parent = function (element) {
  1426. if (typeof element === "string") {
  1427. element = document.querySelector(element);
  1428. }
  1429. if (element == void 0) {
  1430. return;
  1431. }
  1432. if (element instanceof NodeList || element instanceof Array) {
  1433. let resultArray = [];
  1434. element.forEach((item) => {
  1435. resultArray = resultArray.concat(this.parent(item));
  1436. });
  1437. return resultArray;
  1438. } else {
  1439. return element.parentElement;
  1440. }
  1441. };
  1442.  
  1443. /**
  1444. * 将字符串转为Element元素
  1445. * @param {string} html
  1446. * @param {boolean} useParser 是否使用DOMParser来生成元素,有些时候通过DOMParser生成的元素有点问题
  1447. * @param {boolean} isComplete 是否是完整的
  1448. * @returns {HTMLElement}
  1449. * @example
  1450. * // 将字符串转为Element元素
  1451. * DOMUtils.parseHTML("<a href='xxxx'></a>")
  1452. * > <a href="xxxx"></a>
  1453. * @example
  1454. * // 使用DOMParser将字符串转为Element元素
  1455. * DOMUtils.parseHTML("<a href='xxxx'></a>",true)
  1456. * > <a href="xxxx"></a>
  1457. * @example
  1458. * // 由于需要转换的元素是多个元素,将字符串转为完整的Element元素
  1459. * DOMUtils.parseHTML("<a href='xxxx'></a><a href='xxxx'></a>",false, true)
  1460. * > <div><a href="xxxx"></a><a href='xxxx'></a></div>
  1461. * @example
  1462. * // 由于需要转换的元素是多个元素,使用DOMParser将字符串转为完整的Element元素
  1463. * DOMUtils.parseHTML("<a href='xxxx'></a><a href='xxxx'></a>",true, true)
  1464. * > #document
  1465. */
  1466. DOMUtils.parseHTML = function (html, useParser = false, isComplete = false) {
  1467. function parseHTMLByDOMParser() {
  1468. let parser = new DOMParser();
  1469. if (isComplete) {
  1470. return parser.parseFromString(html, "text/html");
  1471. } else {
  1472. return parser.parseFromString(html, "text/html").body.firstChild;
  1473. }
  1474. }
  1475. function parseHTMLByCreateDom() {
  1476. let tempDIV = document.createElement("div");
  1477. tempDIV.innerHTML = html;
  1478. if (isComplete) {
  1479. return tempDIV;
  1480. } else {
  1481. return tempDIV.firstChild;
  1482. }
  1483. }
  1484. if (useParser) {
  1485. return parseHTMLByDOMParser();
  1486. } else {
  1487. return parseHTMLByCreateDom();
  1488. }
  1489. };
  1490.  
  1491. /**
  1492. * 当鼠标移入或移出元素时触发事件
  1493. * @param {HTMLElement|string} element 当前元素
  1494. * @param {(event:Event)=>{}} handler 事件处理函数
  1495. * @example
  1496. * // 监听a.xx元素的移入或移出
  1497. * DOMUtils.hover(document.querySelector("a.xx"),()=>{
  1498. * console.log("移入/移除");
  1499. * })
  1500. * DOMUtils.hover("a.xx",()=>{
  1501. * console.log("移入/移除");
  1502. * })
  1503. */
  1504. DOMUtils.hover = function (element, handler) {
  1505. if (typeof element === "string") {
  1506. element = document.querySelector(element);
  1507. }
  1508. if (element == void 0) {
  1509. return;
  1510. }
  1511. DOMUtils.on(element, "mouseenter", null, handler);
  1512. DOMUtils.on(element, "mouseleave", null, handler);
  1513. };
  1514.  
  1515. /**
  1516. * 显示元素
  1517. * @param {HTMLElement|string} element 当前元素
  1518. * @example
  1519. * // 显示a.xx元素
  1520. * DOMUtils.show(document.querySelector("a.xx"))
  1521. * DOMUtils.show("a.xx")
  1522. */
  1523. DOMUtils.show = function (element) {
  1524. if (typeof element === "string") {
  1525. element = document.querySelector(element);
  1526. }
  1527. if (element == void 0) {
  1528. return;
  1529. }
  1530. element.style.display = "";
  1531. };
  1532.  
  1533. /**
  1534. * 隐藏元素
  1535. * @param {HTMLElement|string} element 当前元素
  1536. * @example
  1537. * // 隐藏a.xx元素
  1538. * DOMUtils.hide(document.querySelector("a.xx"))
  1539. * DOMUtils.hide("a.xx")
  1540. */
  1541. DOMUtils.hide = function (element) {
  1542. if (typeof element === "string") {
  1543. element = document.querySelector(element);
  1544. }
  1545. if (element == void 0) {
  1546. return;
  1547. }
  1548. element.style.display = "none";
  1549. };
  1550.  
  1551. /**
  1552. * 当按键松开时触发事件
  1553. * @param {HTMLElement|string} element 当前元素
  1554. * @param {Function} handler 事件处理函数
  1555. * @example
  1556. * // 监听a.xx元素的按键松开
  1557. * DOMUtils.keyup(document.querySelector("a.xx"),()=>{
  1558. * console.log("按键松开");
  1559. * })
  1560. * DOMUtils.keyup("a.xx",()=>{
  1561. * console.log("按键松开");
  1562. * })
  1563. */
  1564. DOMUtils.keyup = function (element, handler) {
  1565. if (typeof element === "string") {
  1566. element = document.querySelector(element);
  1567. }
  1568. if (element == void 0) {
  1569. return;
  1570. }
  1571. DOMUtils.on(element, "keyup", null, handler);
  1572. };
  1573.  
  1574. /**
  1575. * 当按键按下时触发事件
  1576. * @param {HTMLElement|string} element 当前元素
  1577. * @param {Function} handler 事件处理函数
  1578. * @example
  1579. * // 监听a.xx元素的按键按下
  1580. * DOMUtils.keydown(document.querySelector("a.xx"),()=>{
  1581. * console.log("按键按下");
  1582. * })
  1583. * DOMUtils.keydown("a.xx",()=>{
  1584. * console.log("按键按下");
  1585. * })
  1586. */
  1587. DOMUtils.keydown = function (element, handler) {
  1588. if (typeof element === "string") {
  1589. element = document.querySelector(element);
  1590. }
  1591. if (element == void 0) {
  1592. return;
  1593. }
  1594. DOMUtils.on(element, "keydown", null, handler);
  1595. };
  1596.  
  1597. /**
  1598. * 淡入元素
  1599. * @param {HTMLElement|string} element 当前元素
  1600. * @param {number} [duration=400] 动画持续时间(毫秒),默认400毫秒
  1601. * @param {Function} callback 动画结束的回调
  1602. * @example
  1603. * // 元素a.xx淡入
  1604. * DOMUtils.fadeIn(document.querySelector("a.xx"),2500,()=>{
  1605. * console.log("淡入完毕");
  1606. * })
  1607. * DOMUtils.fadeIn("a.xx",undefined,()=>{
  1608. * console.log("淡入完毕");
  1609. * })
  1610. */
  1611. DOMUtils.fadeIn = function (element, duration = 400, callback) {
  1612. if (typeof element === "string") {
  1613. element = document.querySelector(element);
  1614. }
  1615. if (element == void 0) {
  1616. return;
  1617. }
  1618. element.style.opacity = 0;
  1619. element.style.display = "";
  1620. let start = null;
  1621. let timer = null;
  1622. function step(timestamp) {
  1623. if (!start) start = timestamp;
  1624. let progress = timestamp - start;
  1625. element.style.opacity = Math.min(progress / duration, 1);
  1626. if (progress < duration) {
  1627. window.requestAnimationFrame(step);
  1628. } else {
  1629. if (callback && typeof callback === "function") {
  1630. callback();
  1631. }
  1632. window.cancelAnimationFrame(timer);
  1633. }
  1634. }
  1635. timer = window.requestAnimationFrame(step);
  1636. };
  1637.  
  1638. /**
  1639. * 淡出元素
  1640. * @param {HTMLElement|string} element 当前元素
  1641. * @param {number} [duration=400] 动画持续时间(毫秒),默认400毫秒
  1642. * @param {Function} callback 动画结束的回调
  1643. * @example
  1644. * // 元素a.xx淡出
  1645. * DOMUtils.fadeOut(document.querySelector("a.xx"),2500,()=>{
  1646. * console.log("淡出完毕");
  1647. * })
  1648. * DOMUtils.fadeOut("a.xx",undefined,()=>{
  1649. * console.log("淡出完毕");
  1650. * })
  1651. */
  1652. DOMUtils.fadeOut = function (element, duration = 400, callback) {
  1653. if (typeof element === "string") {
  1654. element = document.querySelector(element);
  1655. }
  1656. if (element == void 0) {
  1657. return;
  1658. }
  1659. element.style.opacity = 1;
  1660. let start = null;
  1661. let timer = null;
  1662. function step(timestamp) {
  1663. if (!start) start = timestamp;
  1664. let progress = timestamp - start;
  1665. element.style.opacity = Math.max(1 - progress / duration, 0);
  1666. if (progress < duration) {
  1667. window.requestAnimationFrame(step);
  1668. } else {
  1669. element.style.display = "none";
  1670. if (typeof callback === "function") {
  1671. callback();
  1672. }
  1673. window.cancelAnimationFrame(timer);
  1674. }
  1675. }
  1676. timer = window.requestAnimationFrame(step);
  1677. };
  1678.  
  1679. /**
  1680. * 切换元素的显示和隐藏状态
  1681. * @param {HTMLElement|string} element 当前元素
  1682. * @example
  1683. * // 如果元素a.xx当前是隐藏,则显示,如果是显示,则隐藏
  1684. * DOMUtils.toggle(document.querySelector("a.xx"))
  1685. * DOMUtils.toggle("a.xx")
  1686. */
  1687. DOMUtils.toggle = function (element) {
  1688. if (typeof element === "string") {
  1689. element = document.querySelector(element);
  1690. }
  1691. if (element == void 0) {
  1692. return;
  1693. }
  1694. if (getComputedStyle(element).getPropertyValue("display") === "none") {
  1695. DOMUtils.show(element);
  1696. } else {
  1697. DOMUtils.hide(element);
  1698. }
  1699. };
  1700. return DOMUtils;
  1701. });

QingJ © 2025

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