DOMUtils

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

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

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

QingJ © 2025

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