DOMUtils

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

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

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

  1. /**
  2. * 自己常用的元素节点工具类
  3. * @copyright GPL-3.0-only
  4. * @author WhiteSevs
  5. * @version 1.1
  6. * @namespace
  7. **/
  8. (function (global, factory) {
  9. typeof exports === "object" && typeof module !== "undefined"
  10. ? (module.exports = factory())
  11. : typeof define === "function" && define.amd
  12. ? define(factory)
  13. : ((global =
  14. typeof globalThis !== "undefined" ? globalThis : global || self),
  15. (global.DOMUtils = factory()));
  16. })(this, function () {
  17. "use strict";
  18. const DOMUtils = {};
  19. /**
  20. * 获取或设置元素的属性值
  21. * @param {HTMLElement|string} element 目标元素
  22. * @param {string} attrName - 属性名
  23. * @param {string} [attrValue] - 属性值(可选)
  24. * @returns {string|undefined} - 如果传入了attrValue,则返回undefined;否则返回属性值
  25. * */
  26. DOMUtils.attr = function (element, attrName, attrValue) {
  27. if (typeof element === "string") {
  28. element = document.querySelector(element);
  29. }
  30. if (attrValue === undefined) {
  31. return element.getAttribute(attrName);
  32. } else {
  33. element.setAttribute(attrName, attrValue);
  34. }
  35. };
  36.  
  37. /**
  38. * 创建元素
  39. * @param {string} tagName 元素类型
  40. * @param {object} property 元素属性
  41. * @returns {Element}
  42. */
  43. DOMUtils.createElement = function (tagName, property) {
  44. let tempElement = document.createElement(tagName);
  45. if (typeof property === "string") {
  46. tempElement.innerHTML = property;
  47. return tempElement;
  48. }
  49. if(property == null){
  50. return tempElement;
  51. }
  52. Object.keys(property).forEach((key) => {
  53. if (key in tempElement && typeof property[key] !== "object") {
  54. tempElement[key] = property[key];
  55. } else {
  56. tempElement.setAttribute(key, property[key]);
  57. }
  58. });
  59. return tempElement;
  60. };
  61.  
  62. /**
  63. * 获取或设置元素的样式属性值
  64. * @param {Element|string} element 目标元素
  65. * @param {string|object} property - 样式属性名或包含多个属性名和属性值的对象
  66. * @param {string} [value] - 样式属性值(可选)
  67. * @returns {string|undefined} - 如果传入了value,则返回undefined;否则返回样式属性值
  68. * */
  69. DOMUtils.css = function (element, property, value) {
  70. /**
  71. * 把纯数字没有px的加上
  72. */
  73. function handlePixe(propertyName, propertyValue) {
  74. let allowAddPixe = ["width", "height", "top", "left", "right", "bottom"];
  75. if (typeof propertyValue === "number") {
  76. propertyValue = propertyValue.toString();
  77. }
  78. if (
  79. typeof propertyValue === "string" &&
  80. allowAddPixe.includes(propertyName) &&
  81. propertyValue.match(/[0-9]$/gi)
  82. ) {
  83. propertyValue = propertyValue + "px";
  84. }
  85. return propertyValue;
  86. }
  87. if (typeof element === "string") {
  88. element = document.querySelector(element);
  89. }
  90. if (typeof property === "string") {
  91. if (value === undefined) {
  92. return element.style[property];
  93. } else {
  94. if (value === "string" && value.includes("!important")) {
  95. element.style.setProperty(property, value, "important");
  96. } else {
  97. value = handlePixe(property, value);
  98. element.style.setProperty(property, value);
  99. }
  100. }
  101. } else if (typeof property === "object") {
  102. for (let prop in property) {
  103. if (
  104. typeof property[prop] === "string" &&
  105. property[prop].includes("!important")
  106. ) {
  107. element.style.setProperty(prop, property[prop], "important");
  108. } else {
  109. property[prop] = handlePixe(prop, property[prop]);
  110. element.style.setProperty(prop, property[prop]);
  111. }
  112. }
  113. }
  114. };
  115. /**
  116. * 获取或设置元素的文本内容
  117. * @param {Element|element} element 目标元素
  118. * @param {string} [text] - 文本内容(可选)
  119. * @returns {string|undefined} - 如果传入了text,则返回undefined;否则返回文本内容
  120. * */
  121. DOMUtils.text = function (element, text) {
  122. if (typeof element === "string") {
  123. element = document.querySelector(element);
  124. }
  125. if (text === undefined) {
  126. return element.textContent;
  127. } else {
  128. if ("textContent" in element) {
  129. element.textContent = text;
  130. }
  131. }
  132. };
  133. /**
  134. * 获取或设置元素的HTML内容
  135. * @param {Element|string} element 目标元素
  136. * @param {string} [html] - HTML内容(可选)
  137. * @returns {string|undefined} - 如果传入了html,则返回undefined;否则返回HTML内容
  138. * */
  139. DOMUtils.html = function (element, html) {
  140. if (typeof element === "string") {
  141. element = document.querySelector(element);
  142. }
  143. if (html === undefined) {
  144. return element.innerHTML;
  145. } else {
  146. if ("innerHTML" in element) {
  147. element.innerHTML = html;
  148. }
  149. }
  150. };
  151. /**
  152. * 绑定或触发元素的click事件
  153. * @param {Element|string} element 目标元素
  154. * @param {function} [handler] - 事件处理函数(可选)
  155. * @returns {DOMUtils} - 原型链
  156. * @function
  157. * */
  158. DOMUtils.click = function (element, handler) {
  159. if (typeof element === "string") {
  160. element = document.querySelector(element);
  161. }
  162. if (handler === undefined) {
  163. DOMUtils.trigger(element, "click");
  164. } else {
  165. DOMUtils.on(element, "click", null, handler);
  166. }
  167. return this;
  168. };
  169.  
  170. /**
  171. * 绑定或触发元素的blur事件
  172. * @param {Element|string} element 目标元素
  173. * @param {function} [handler] - 事件处理函数(可选)
  174. * @returns {DOMUtils} - 原型链
  175. * */
  176. DOMUtils.blur = function (element, handler) {
  177. if (typeof element === "string") {
  178. element = document.querySelector(element);
  179. }
  180. if (handler === undefined) {
  181. DOMUtils.trigger(element, "blur");
  182. } else {
  183. DOMUtils.on(element, "blur", null, handler);
  184. }
  185. return this;
  186. };
  187. /**
  188. * 绑定或触发元素的focus事件
  189. * @param {Element|string} element 目标元素
  190. * @param {function} [handler] - 事件处理函数(可选)
  191. * @returns {DOMUtils} - 原型链
  192. * */
  193. DOMUtils.focus = function (element, handler) {
  194. if (typeof element === "string") {
  195. element = document.querySelector(element);
  196. }
  197. if (handler === undefined) {
  198. DOMUtils.trigger(element, "focus");
  199. } else {
  200. DOMUtils.on(element, "focus", null, handler);
  201. }
  202. return this;
  203. };
  204. /**
  205. * 获取或设置元素的value属性值
  206. * @param {Element|string} element 目标元素
  207. * @param {string} [value] - value属性值(可选)
  208. * @returns {string|undefined} - 如果传入了value,则返回undefined;否则返回value属性值
  209. * */
  210. DOMUtils.val = function (element, value) {
  211. if (typeof element === "string") {
  212. element = document.querySelector(element);
  213. }
  214. if (value === undefined) {
  215. if (
  216. element.localName === "input" &&
  217. (element.type === "checkbox" || element.type === "radio")
  218. ) {
  219. return element.checked;
  220. } else {
  221. return element.value;
  222. }
  223. } else {
  224. if (
  225. element.localName === "input" &&
  226. (element.type === "checkbox" || element.type === "radio")
  227. ) {
  228. element.checked = !!value;
  229. } else {
  230. element.value = value;
  231. }
  232. }
  233. };
  234. /**
  235. * 获取或设置元素的属性值
  236. * @param {Element|string} element 目标元素
  237. * @param {string} propName - 属性名
  238. * @param {string} [propValue] - 属性值(可选)
  239. * @returns {string|undefined} - 如果传入了propValue,则返回undefined;否则返回属性值
  240. * */
  241. DOMUtils.prop = function (element, propName, propValue) {
  242. if (typeof element === "string") {
  243. element = document.querySelector(element);
  244. }
  245. if (propValue === undefined) {
  246. return element[propName];
  247. } else {
  248. element[propName] = propValue;
  249. }
  250. };
  251.  
  252. /**
  253. * 移除元素的属性
  254. * @param {Element|string} element 目标元素
  255. * @param {string} attrName - 属性名
  256. * @returns {DOMUtils} - 原型链
  257. * */
  258. DOMUtils.removeAttr = function (element, attrName) {
  259. if (typeof element === "string") {
  260. element = document.querySelector(element);
  261. }
  262. element.removeAttribute(attrName);
  263. return this;
  264. };
  265.  
  266. /**
  267. * 移除元素class名
  268. * @param {Element|string} element 目标元素
  269. * @param {string} className class名
  270. * @returns {DOMUtils} 原型链
  271. */
  272. DOMUtils.removeClass = function (element, className) {
  273. if (typeof element === "string") {
  274. element = document.querySelector(element);
  275. }
  276. element.classList.remove(className);
  277. return this;
  278. };
  279.  
  280. /**
  281. * 移除元素的属性
  282. * @param {Element|string} element 目标元素
  283. * @param {string} propName - 属性名
  284. * @returns {DOMUtils} - 原型链
  285. * */
  286. DOMUtils.removeProp = function (element, propName) {
  287. if (typeof element === "string") {
  288. element = document.querySelector(element);
  289. }
  290. delete element[propName];
  291. return this;
  292. };
  293.  
  294. /**
  295. * 将一个元素替换为另一个元素
  296. * @param {Element|string} element 目标元素
  297. * @param {Element|string} newElement 新元素
  298. * @returns {DOMUtils} 原型链
  299. */
  300. DOMUtils.replaceWith = function (element, newElement) {
  301. if (typeof element === "string") {
  302. element = document.querySelector(element);
  303. }
  304. if (typeof newElement === "string") {
  305. newElement = DOMUtils.parseHTML(newElement, false, false);
  306. }
  307. if (element instanceof NodeList || element instanceof Array) {
  308. element.forEach((item) => {
  309. DOMUtils.replaceWith(item, newElement);
  310. });
  311. } else {
  312. element.parentElement.replaceChild(newElement, element);
  313. }
  314. return this;
  315. };
  316.  
  317. /**
  318. * 给元素添加class
  319. * @param {Element|string} element 目标元素
  320. * @param {string} className - class名
  321. * @returns {DOMUtils} - 原型链
  322. * */
  323. DOMUtils.addClass = function (element, className) {
  324. if (typeof element === "string") {
  325. element = document.querySelector(element);
  326. }
  327. element.classList.add(className);
  328. return this;
  329. };
  330. /**
  331. * 函数在元素内部末尾添加子元素或HTML字符串
  332. * @param {Element|string} element 目标元素
  333. * @param {object|string} content - 子元素或HTML字符串
  334. * @returns {DOMUtils} - 原型链
  335. * */
  336. DOMUtils.append = function (element, content) {
  337. if (typeof element === "string") {
  338. element = document.querySelector(element);
  339. }
  340. if (typeof content === "string") {
  341. element.insertAdjacentHTML("beforeend", content);
  342. } else {
  343. element.appendChild(content);
  344. }
  345. return this;
  346. };
  347.  
  348. /**
  349. * 函数 在元素内部开头添加子元素或HTML字符串
  350. * @param {Element|string} element 目标元素
  351. * @param {object|string} content - 子元素或HTML字符串
  352. * @returns {DOMUtils} - 原型链
  353. * */
  354. DOMUtils.prepend = function (element, content) {
  355. if (typeof element === "string") {
  356. element = document.querySelector(element);
  357. }
  358. if (typeof content === "string") {
  359. element.insertAdjacentHTML("afterbegin", content);
  360. } else {
  361. element.insertBefore(content, element.firstChild);
  362. }
  363. return this;
  364. };
  365. /**
  366. * 在元素后面添加兄弟元素或HTML字符串
  367. * @param {Element|string} element 目标元素
  368. * @param {object|string} content - 兄弟元素或HTML字符串
  369. * @returns {DOMUtils} - 原型链
  370. * */
  371. DOMUtils.after = function (element, content) {
  372. if (typeof element === "string") {
  373. element = document.querySelector(element);
  374. }
  375. if (typeof content === "string") {
  376. element.insertAdjacentHTML("afterend", content);
  377. } else {
  378. element.parentElement.insertBefore(content, element.nextSibling);
  379. }
  380. return this;
  381. };
  382.  
  383. /**
  384. * 在元素前面添加兄弟元素或HTML字符串
  385. * @param {Element|string} element 目标元素
  386. * @param {object|string} content - 兄弟元素或HTML字符串
  387. * @returns {DOMUtils} - 原型链
  388. * */
  389. DOMUtils.before = function (element, content) {
  390. if (typeof element === "string") {
  391. element = document.querySelector(element);
  392. }
  393. if (typeof content === "string") {
  394. element.insertAdjacentHTML("beforebegin", content);
  395. } else {
  396. element.parentElement.insertBefore(content, element);
  397. }
  398. return this;
  399. };
  400.  
  401. /**
  402. * 移除元素
  403. * @param {Element|string|NodeList} element 目标元素
  404. * @returns {DOMUtils} - 原型链
  405. * */
  406. DOMUtils.remove = function (element) {
  407. if (typeof element === "string") {
  408. element = document.querySelectorAll(element);
  409. }
  410. if (element instanceof NodeList || element instanceof Array) {
  411. element.forEach(function (item) {
  412. DOMUtils.remove(item);
  413. });
  414. } else {
  415. element.remove();
  416. }
  417. return this;
  418. };
  419. /**
  420. * 移除元素的所有子元素
  421. * @param {Element|string} element 目标元素
  422. * @returns {DOMUtils} - 原型链
  423. * */
  424. DOMUtils.empty = function (element) {
  425. if (typeof element === "string") {
  426. element = document.querySelector(element);
  427. }
  428. while (element.firstChild) {
  429. element.removeChild(element.firstChild);
  430. }
  431. return this;
  432. };
  433. /**
  434. * 绑定事件
  435. * @param {Element|string} element 需要绑定的元素
  436. * @param {String|Array} eventType 需要监听的事件
  437. * @param {HTMLElement?} selector 子元素选择器
  438. * @param {Function} callback 事件触发的回调函数
  439. * @param {Boolean} capture 表示事件是否在捕获阶段触发。默认为false,即在冒泡阶段触发
  440. * @param {Boolean} once 表示事件是否只触发一次。默认为false
  441. * @param {Boolean} passive 表示事件监听器是否不会调用preventDefault()。默认为false
  442. * @returns {DOMUtils} - 原型链
  443. * @function
  444. */
  445. DOMUtils.on = function (
  446. element,
  447. eventType,
  448. selector,
  449. callback,
  450. capture = false,
  451. once = false,
  452. passive = false
  453. ) {
  454. if (typeof element === "string") {
  455. element = document.querySelector(element);
  456. }
  457. if (element == null) {
  458. return this;
  459. }
  460. let eventTypeList = [];
  461. if (Array.isArray(eventType)) {
  462. eventTypeList = eventType;
  463. } else if (typeof eventType === "string") {
  464. eventTypeList = eventType.split(" ");
  465. }
  466. if (typeof selector === "function") {
  467. /* 这是为没有selector的情况 */
  468. callback = selector;
  469. selector = null;
  470. }
  471. eventTypeList.forEach((_eventType_) => {
  472. if (selector) {
  473. element.addEventListener(
  474. _eventType_,
  475. function (event) {
  476. let target = event.target;
  477. if (target.matches(selector)) {
  478. callback.call(target, event);
  479. }
  480. },
  481. capture,
  482. once,
  483. passive
  484. );
  485. } else {
  486. element.addEventListener(
  487. _eventType_,
  488. function (event) {
  489. callback.call(event.target, event);
  490. },
  491. capture,
  492. once,
  493. passive
  494. );
  495. }
  496. });
  497.  
  498. if (callback && callback.delegate) {
  499. element.setAttribute("data-delegate", selector);
  500. }
  501.  
  502. let events = element.events || {};
  503. events[eventType] = events[eventType] || [];
  504. events[eventType].push({
  505. selector: selector,
  506. callback: callback,
  507. });
  508. element.events = events;
  509.  
  510. return this;
  511. };
  512. /**
  513. * 取消绑定事件
  514. * @param {Element|string} element 需要取消绑定的元素
  515. * @param {String|Array} eventType 需要取消监听的事件
  516. * @param {HTMLElement} selector 子元素选择器
  517. * @param {Function} callback 事件触发的回调函数
  518. * @param {Boolean} useCapture 表示事件是否在捕获阶段处理,它是一个可选参数,默认为false,表示在冒泡阶段处理事件。
  519. * 如果在添加事件监听器时指定了useCapture为true,则在移除事件监听器时也必须指定为true
  520. * @returns {DOMUtils} - 原型链
  521. */
  522. DOMUtils.off = function (
  523. element,
  524. eventType,
  525. selector,
  526. callback,
  527. useCapture = false
  528. ) {
  529. if (typeof element === "string") {
  530. element = document.querySelector(element);
  531. }
  532. let events = element.events || {};
  533. let eventTypeList = [];
  534. if (!eventType) {
  535. for (let type in events) {
  536. eventTypeList = [...eventTypeList, type];
  537. }
  538. } else if (Array.isArray(eventType)) {
  539. eventTypeList = eventType;
  540. } else if (typeof eventType === "string") {
  541. eventTypeList = eventType.split(" ");
  542. }
  543. eventTypeList.forEach((_eventType_) => {
  544. let handlers = events[eventType] || [];
  545. for (let i = 0; i < handlers.length; i++) {
  546. if (
  547. (!selector || handlers[i].selector === selector) &&
  548. (!callback || handlers[i].callback === callback)
  549. ) {
  550. element.removeEventListener(
  551. _eventType_,
  552. handlers[i].callback,
  553. useCapture
  554. );
  555. handlers.splice(i--, 1);
  556. }
  557. }
  558. if (handlers.length === 0) {
  559. delete events[eventType];
  560. }
  561. });
  562. element.events = events;
  563. return this;
  564. };
  565. /**
  566. * 主动触发事件
  567. * @param {Element|string} element 需要触发的元素
  568. * @param {String|Array} eventType 需要触发的事件
  569. * @returns {DOMUtils} - 原型链
  570. */
  571. DOMUtils.trigger = function (element, eventType) {
  572. if (typeof element === "string") {
  573. element = document.querySelector(element);
  574. }
  575. let events = element.events || {};
  576. let eventTypeList = [];
  577. if (!eventType) {
  578. for (let type in events) {
  579. eventTypeList = [...eventTypeList, type];
  580. }
  581. } else if (Array.isArray(eventType)) {
  582. eventTypeList = eventType;
  583. } else if (typeof eventType === "string") {
  584. eventTypeList = eventType.split(" ");
  585. }
  586. eventTypeList.forEach((_eventType_) => {
  587. let event = new Event(_eventType_);
  588. element.dispatchEvent(event);
  589. });
  590. return this;
  591. };
  592. /**
  593. * 设置或返回被选元素相对于文档的偏移坐标
  594. * @param {Element|string} element
  595. * @returns {Object}
  596. */
  597. DOMUtils.offset = function (element) {
  598. if (typeof element === "string") {
  599. element = document.querySelector(element);
  600. }
  601. let rect = element.getBoundingClientRect();
  602. let win = window;
  603. return {
  604. top: rect.top + win.scrollY,
  605. left: rect.left + win.scrollX,
  606. };
  607. };
  608. /**
  609. * 获取元素的宽度
  610. * @param {Element|string} element - 要获取宽度的元素
  611. * @returns {Number} - 元素的宽度,单位为像素
  612. */
  613. DOMUtils.width = function (element) {
  614. if (element == window) {
  615. return window.document.documentElement.clientWidth;
  616. }
  617. if (typeof element === "string") {
  618. element = document.querySelector(element);
  619. }
  620. if (element.nodeType === 9) {
  621. /* 文档节点 */
  622. return Math.max(
  623. element.body.scrollWidth,
  624. element.documentElement.scrollWidth,
  625. element.body.offsetWidth,
  626. element.documentElement.offsetWidth,
  627. element.documentElement.clientWidth
  628. );
  629. }
  630. let oldCSS_display = element.style.display;
  631. let oldCSS_visibility = element.style.visibility;
  632. let oldCSS_position = element.style.position;
  633. element.style.display = "block";
  634. element.style.visibility = "hidden";
  635. element.style.position = "absolute";
  636. let view = element.ownerDocument.defaultView;
  637. if (!view || !view.opener) {
  638. view = window;
  639. }
  640. let styles = view.getComputedStyle(element);
  641. let elementWidth =
  642. element.clientWidth -
  643. parseFloat(styles.paddingLeft) -
  644. parseFloat(styles.paddingRight);
  645. element.style.display = oldCSS_display;
  646. element.style.visibility = oldCSS_visibility;
  647. element.style.position = oldCSS_position;
  648. return elementWidth;
  649. };
  650. /**
  651. * 获取元素的高度
  652. * @param {Element|string} element - 要获取高度的元素
  653. * @returns {Number} - 元素的高度,单位为像素
  654. */
  655. DOMUtils.height = function (element) {
  656. if (element == window) {
  657. return window.document.documentElement.clientHeight;
  658. }
  659. if (typeof element === "string") {
  660. element = document.querySelector(element);
  661. }
  662. if (element.nodeType === 9) {
  663. /* 文档节点 */
  664. return Math.max(
  665. element.body.scrollHeight,
  666. element.documentElement.scrollHeight,
  667. element.body.offsetHeight,
  668. element.documentElement.offsetHeight,
  669. element.documentElement.clientHeight
  670. );
  671. }
  672. let oldCSS_display = element.style.display;
  673. let oldCSS_visibility = element.style.visibility;
  674. let oldCSS_position = element.style.position;
  675. element.style.display = "block";
  676. element.style.visibility = "hidden";
  677. element.style.position = "absolute";
  678. let view = element.ownerDocument.defaultView;
  679. if (!view || !view.opener) {
  680. view = window;
  681. }
  682. let styles = view.getComputedStyle(element);
  683. let elementHeight =
  684. element.clientHeight -
  685. parseFloat(styles.paddingTop) -
  686. parseFloat(styles.paddingBottom);
  687. element.style.display = oldCSS_display;
  688. element.style.visibility = oldCSS_visibility;
  689. element.style.position = oldCSS_position;
  690. return elementHeight;
  691. };
  692. /**
  693. * 获取元素的外部宽度(包括边框和外边距)
  694. * @param {Element|string} element - 要获取外部宽度的元素
  695. * @returns {Number} - 元素的外部宽度,单位为像素
  696. */
  697. DOMUtils.outerWidth = function (element) {
  698. if (element == window) {
  699. return window.innerWidth;
  700. }
  701. if (typeof element === "string") {
  702. element = document.querySelector(element);
  703. }
  704. let style = getComputedStyle(element, null);
  705. return (
  706. element.offsetWidth +
  707. parseFloat(style.marginLeft) +
  708. parseFloat(style.marginRight)
  709. );
  710. };
  711. /**
  712. * 获取元素的外部高度(包括边框和外边距)
  713. * @param {Element|string} element - 要获取外部高度的元素
  714. * @returns {Number} - 元素的外部高度,单位为像素
  715. */
  716. DOMUtils.outerHeight = function (element) {
  717. if (element == window) {
  718. return window.innerHeight;
  719. }
  720. if (typeof element === "string") {
  721. element = document.querySelector(element);
  722. }
  723. let style = getComputedStyle(element, null);
  724. return (
  725. element.offsetHeight +
  726. parseFloat(style.marginTop) +
  727. parseFloat(style.marginBottom)
  728. );
  729. };
  730.  
  731. /**
  732. * 等待文档加载完成后执行指定的函数
  733. * @param {Function} callback - 需要执行的函数
  734. * @returns {DOMUtils} - 原型链
  735. */
  736. DOMUtils.ready = function (callback) {
  737. if (document.readyState !== "loading") {
  738. callback();
  739. } else {
  740. DOMUtils.on(document, "DOMContentLoaded", null, callback);
  741. }
  742. return this;
  743. };
  744.  
  745. /**
  746. * 在一定时间内改变元素的样式属性,实现动画效果
  747. * @param {Element|string} element - 需要进行动画的元素
  748. * @param {Object} styles - 动画结束时元素的样式属性
  749. * @param {Number} [duration=1000] - 动画持续时间,单位为毫秒
  750. * @param {Function} [callback=null] - 动画结束后执行的函数
  751. * @returns {DOMUtils} - 原型链
  752. */
  753. DOMUtils.animate = function (
  754. element,
  755. styles,
  756. duration = 1000,
  757. callback = null
  758. ) {
  759. if (typeof element === "string") {
  760. element = document.querySelector(element);
  761. }
  762. if (typeof duration !== "number" || duration <= 0) {
  763. throw new TypeError("duration must be a positive number");
  764. }
  765. if (typeof callback !== "function" && callback !== null) {
  766. throw new TypeError("callback must be a function or null");
  767. }
  768. if (typeof styles !== "object" || styles === null) {
  769. throw new TypeError("styles must be an object");
  770. }
  771. if (Object.keys(styles).length === 0) {
  772. throw new Error("styles must contain at least one property");
  773. }
  774. let start = performance.now();
  775. let from = {};
  776. let to = {};
  777. for (let prop in styles) {
  778. from[prop] = element.style[prop] || getComputedStyle(element)[prop];
  779. to[prop] = styles[prop];
  780. }
  781. let timer = setInterval(function () {
  782. let timePassed = performance.now() - start;
  783. let progress = timePassed / duration;
  784. if (progress > 1) {
  785. progress = 1;
  786. }
  787. for (let prop in styles) {
  788. element.style[prop] =
  789. from[prop] + (to[prop] - from[prop]) * progress + "px";
  790. }
  791. if (progress === 1) {
  792. clearInterval(timer);
  793. if (callback) {
  794. callback();
  795. }
  796. }
  797. }, 10);
  798. return this;
  799. };
  800.  
  801. /**
  802. * 将一个元素包裹在指定的HTML元素中
  803. * @param {Element|string} element 要包裹的元素
  804. * @param {string} wrapperHTML 要包裹的HTML元素的字符串表示形式
  805. * @returns {DOMUtils} - 原型链
  806. */
  807. DOMUtils.wrap = function (element, wrapperHTML) {
  808. if (typeof element === "string") {
  809. element = document.querySelector(element);
  810. }
  811. // 创建一个新的div元素,并将wrapperHTML作为其innerHTML
  812. let wrapper = document.createElement("div");
  813. wrapper.innerHTML = wrapperHTML;
  814.  
  815. // 将要包裹的元素插入到wrapper中
  816. element.parentElement.insertBefore(wrapper, element);
  817.  
  818. // 将要包裹的元素移动到wrapper中
  819. wrapper.insertBefore(element, wrapper.firstChild);
  820. return this;
  821. };
  822. /**
  823. * 获取当前元素的前一个兄弟元素
  824. * @param {Element|string} element - 当前元素
  825. * @returns {Element} - 前一个兄弟元素
  826. */
  827. DOMUtils.prev = function (element) {
  828. if (typeof element === "string") {
  829. element = document.querySelector(element);
  830. }
  831. return element.previousElementSibling;
  832. };
  833.  
  834. /**
  835. * 获取当前元素的后一个兄弟元素
  836. * @param {Element|string} element - 当前元素
  837. * @returns {Element} - 后一个兄弟元素
  838. */
  839. DOMUtils.next = function (element) {
  840. if (typeof element === "string") {
  841. element = document.querySelector(element);
  842. }
  843. return element.nextElementSibling;
  844. };
  845.  
  846.  
  847. /**
  848. * 获取当前元素的所有兄弟元素
  849. * @param {Element|string} element - 当前元素
  850. * @returns {Array} - 所有兄弟元素
  851. */
  852. DOMUtils.siblings = function (element) {
  853. if (typeof element === "string") {
  854. element = document.querySelector(element);
  855. }
  856. return Array.from(element.parentElement.children).filter(
  857. (child) => child !== element
  858. );
  859. };
  860.  
  861. /**
  862. * 获取当前元素的父元素
  863. * @param {Element|NodeList|string} element - 当前元素
  864. * @returns {Element|Array} - 父元素
  865. */
  866. DOMUtils.parent = function (element) {
  867. if (typeof element === "string") {
  868. element = document.querySelector(element);
  869. }
  870. if (element instanceof NodeList || element instanceof Array) {
  871. let resultArray = [];
  872. element.forEach((item) => {
  873. resultArray = resultArray.concat(this.parent(item));
  874. });
  875. return resultArray;
  876. } else {
  877. return element.parentElement;
  878. }
  879. };
  880.  
  881. /**
  882. * 将字符串转为Element元素
  883. * @param {string} html
  884. * @param {boolean} useParser 是否使用DOMParser来生成元素,有些时候通过DOMParser生成的元素有点问题
  885. * @param {boolean} isComplete 是否是完整的
  886. * @returns {Element}
  887. */
  888. DOMUtils.parseHTML = function (html, useParser = false, isComplete = false) {
  889. function parseHTMLByDOMParser() {
  890. let parser = new DOMParser();
  891. if (isComplete) {
  892. return parser.parseFromString(html, "text/html");
  893. } else {
  894. return parser.parseFromString(html, "text/html").body.firstChild;
  895. }
  896. }
  897. function parseHTMLByCreateDom() {
  898. let tempDIV = document.createElement("div");
  899. tempDIV.innerHTML = html;
  900. if (isComplete) {
  901. return tempDIV;
  902. } else {
  903. return tempDIV.firstChild;
  904. }
  905. }
  906. if (useParser) {
  907. return parseHTMLByDOMParser();
  908. } else {
  909. return parseHTMLByCreateDom();
  910. }
  911. };
  912.  
  913. /**
  914. * 当鼠标移入或移出元素时触发事件
  915. * @param {Element|string} element - 当前元素
  916. * @param {Function} handler - 事件处理函数
  917. * @returns {DOMUtils} - 原型链
  918. */
  919. DOMUtils.hover = function (element, handler) {
  920. if (typeof element === "string") {
  921. element = document.querySelector(element);
  922. }
  923. DOMUtils.on(element, "mouseenter", null, handler);
  924. DOMUtils.on(element, "mouseleave", null, handler);
  925. return this;
  926. };
  927.  
  928. /**
  929. * 显示元素
  930. * @param {Element|string} element - 当前元素
  931. * @returns {DOMUtils} - 原型链
  932. */
  933. DOMUtils.show = function (element) {
  934. if (typeof element === "string") {
  935. element = document.querySelector(element);
  936. }
  937. element.style.display = "";
  938. return this;
  939. };
  940.  
  941. /**
  942. * 隐藏元素
  943. * @param {Element|string} element - 当前元素
  944. * @returns {DOMUtils} - 原型链
  945. */
  946. DOMUtils.hide = function (element) {
  947. if (typeof element === "string") {
  948. element = document.querySelector(element);
  949. }
  950. element.style.display = "none";
  951. return this;
  952. };
  953.  
  954. /**
  955. * 当按键松开时触发事件
  956. * @param {Element|string} element - 当前元素
  957. * @param {Function} handler - 事件处理函数
  958. * @returns {DOMUtils} - 原型链
  959. */
  960. DOMUtils.keyup = function (element, handler) {
  961. if (typeof element === "string") {
  962. element = document.querySelector(element);
  963. }
  964. DOMUtils.on(element, "keyup", null, handler);
  965. return this;
  966. };
  967.  
  968. /**
  969. * 当按键按下时触发事件
  970. * @param {Element|string} element - 当前元素
  971. * @param {Function} handler - 事件处理函数
  972. * @returns {DOMUtils} - 原型链
  973. */
  974. DOMUtils.keydown = function (element, handler) {
  975. if (typeof element === "string") {
  976. element = document.querySelector(element);
  977. }
  978. DOMUtils.on(element, "keydown", null, handler);
  979. return this;
  980. };
  981.  
  982. /**
  983. * 淡入元素
  984. * @param {Element|string} element - 当前元素
  985. * @param {Number} duration - 动画持续时间(毫秒)
  986. * @param {Function} callback 动画结束的回调
  987. * @returns {DOMUtils} - 原型链
  988. */
  989. DOMUtils.fadeIn = function (element, duration = 400, callback) {
  990. if (typeof element === "string") {
  991. element = document.querySelector(element);
  992. }
  993. element.style.opacity = 0;
  994. element.style.display = "";
  995. let start = null;
  996. let timer = null;
  997. function step(timestamp) {
  998. if (!start) start = timestamp;
  999. let progress = timestamp - start;
  1000. element.style.opacity = Math.min(progress / duration, 1);
  1001. if (progress < duration) {
  1002. window.requestAnimationFrame(step);
  1003. } else {
  1004. if (callback && typeof callback === "function") {
  1005. callback();
  1006. }
  1007. window.cancelAnimationFrame(timer);
  1008. }
  1009. }
  1010. timer = window.requestAnimationFrame(step);
  1011. return this;
  1012. };
  1013.  
  1014. /**
  1015. * 淡出元素
  1016. * @param {Element|string} element - 当前元素
  1017. * @param {Number} duration - 动画持续时间(毫秒)
  1018. * @param {Function} callback 动画结束的回调
  1019. * @returns {DOMUtils} - 原型链
  1020. */
  1021. DOMUtils.fadeOut = function (element, duration = 400, callback) {
  1022. if (typeof element === "string") {
  1023. element = document.querySelector(element);
  1024. }
  1025. element.style.opacity = 1;
  1026. let start = null;
  1027. let timer = null;
  1028. function step(timestamp) {
  1029. if (!start) start = timestamp;
  1030. let progress = timestamp - start;
  1031. element.style.opacity = Math.max(1 - progress / duration, 0);
  1032. if (progress < duration) {
  1033. window.requestAnimationFrame(step);
  1034. } else {
  1035. element.style.display = "none";
  1036. if (typeof callback === "function") {
  1037. callback();
  1038. }
  1039. window.cancelAnimationFrame(timer);
  1040. }
  1041. }
  1042. timer = window.requestAnimationFrame(step);
  1043. return this;
  1044. };
  1045.  
  1046. /**
  1047. * 为指定元素的子元素绑定事件
  1048. * @param {Element|string} element - 当前元素
  1049. * @param {String} selector - 子元素选择器
  1050. * @param {String} type - 事件类型
  1051. * @param {Function} handler - 事件处理函数
  1052. * @returns {DOMUtils} - 原型链
  1053. */
  1054. DOMUtils.delegate = function (element, selector, type, handler) {
  1055. if (typeof element === "string") {
  1056. element = document.querySelector(element);
  1057. }
  1058. element.addEventListener(type, (event) => {
  1059. let target = event.target.closest(selector);
  1060. if (target && element.contains(target)) {
  1061. handler.call(target, event);
  1062. }
  1063. });
  1064. return this;
  1065. };
  1066.  
  1067. /**
  1068. * 切换元素的显示和隐藏状态
  1069. * @param {Element|string} element - 当前元素
  1070. * @returns {DOMUtils} - 原型链
  1071. */
  1072. DOMUtils.toggle = function (element) {
  1073. if (typeof element === "string") {
  1074. element = document.querySelector(element);
  1075. }
  1076. if (element.style.display === "none") {
  1077. DOMUtils.show(element);
  1078. } else {
  1079. DOMUtils.hide(element);
  1080. }
  1081. return this;
  1082. };
  1083. return DOMUtils;
  1084. });

QingJ © 2025

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