DOMUtils

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

当前为 2023-09-18 提交的版本,查看 最新版本

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

QingJ © 2025

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