DOMUtils

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

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

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

QingJ © 2025

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