DOMUtils

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

当前为 2024-06-22 提交的版本,查看 最新版本

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

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.DOMUtils = factory());
  5. })(this, (function () { 'use strict';
  6.  
  7. const DOMUtilsCoreDefaultEnv = {
  8. document: document,
  9. window: window,
  10. globalThis: globalThis,
  11. self: self,
  12. };
  13. const DOMUtilsCoreEnv = {
  14. document: document,
  15. window: window,
  16. globalThis: globalThis,
  17. self: self,
  18. };
  19. const DOMUtilsCore = {
  20. init(option) {
  21. if (!option) {
  22. option = Object.assign({}, DOMUtilsCoreDefaultEnv);
  23. }
  24. Object.assign(DOMUtilsCoreEnv, option);
  25. },
  26. get document() {
  27. return DOMUtilsCoreEnv.document;
  28. },
  29. get window() {
  30. return DOMUtilsCoreEnv.window;
  31. },
  32. get globalThis() {
  33. return DOMUtilsCoreEnv.globalThis;
  34. },
  35. get self() {
  36. return DOMUtilsCoreEnv.self;
  37. },
  38. };
  39.  
  40. /** 通用工具类 */
  41. const DOMUtilsCommonUtils = {
  42. /**
  43. * 判断元素是否已显示或已连接
  44. * @param element
  45. */
  46. isShow(element) {
  47. return Boolean(element.getClientRects().length);
  48. },
  49. /**
  50. * 用于显示元素并获取它的高度宽度等其它属性
  51. * @param element
  52. */
  53. showElement(element) {
  54. let dupNode = element.cloneNode(true);
  55. dupNode.setAttribute("style", "visibility: hidden !important;display:block !important;");
  56. DOMUtilsCore.document.documentElement.appendChild(dupNode);
  57. return {
  58. /**
  59. * 恢复修改的style
  60. */
  61. recovery() {
  62. dupNode.remove();
  63. },
  64. };
  65. },
  66. /**
  67. * 获取元素上的Float格式的属性px
  68. * @param element
  69. * @param styleName style名
  70. */
  71. getStyleValue(element, styleName) {
  72. let view = null;
  73. let styles = null;
  74. if (element instanceof CSSStyleDeclaration) {
  75. /* 直接就获取了style属性 */
  76. styles = element;
  77. }
  78. else {
  79. view = element.ownerDocument.defaultView;
  80. if (!view || !view.opener) {
  81. view = window;
  82. }
  83. styles = view.getComputedStyle(element);
  84. }
  85. let value = parseFloat(styles[styleName]);
  86. if (isNaN(value)) {
  87. return 0;
  88. }
  89. else {
  90. return value;
  91. }
  92. },
  93. /**
  94. * 判断是否是window,例如window、self、globalThis
  95. * @param target
  96. */
  97. isWin(target) {
  98. if (typeof target !== "object") {
  99. return false;
  100. }
  101. if (target instanceof Node) {
  102. return false;
  103. }
  104. if (target === globalThis) {
  105. return true;
  106. }
  107. if (target === window) {
  108. return true;
  109. }
  110. if (target === self) {
  111. return true;
  112. }
  113. if (target === DOMUtilsCore.globalThis) {
  114. return true;
  115. }
  116. if (target === DOMUtilsCore.window) {
  117. return true;
  118. }
  119. if (target === DOMUtilsCore.self) {
  120. return true;
  121. }
  122. if (typeof unsafeWindow !== "undefined" &&
  123. target === unsafeWindow) {
  124. return true;
  125. }
  126. if (target?.Math?.toString() !== "[object Math]") {
  127. return false;
  128. }
  129. return true;
  130. },
  131. /**
  132. * 删除对象上的属性
  133. * @param target
  134. * @param propName
  135. */
  136. delete(target, propName) {
  137. if (typeof Reflect === "object" && Reflect.deleteProperty) {
  138. Reflect.deleteProperty(target, propName);
  139. }
  140. else {
  141. delete target[propName];
  142. }
  143. },
  144. };
  145.  
  146. /* 数据 */
  147. const DOMUtilsData = {
  148. /** .on绑定的事件 */
  149. SymbolEvents: Symbol("events_" + (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)),
  150. };
  151.  
  152. const OriginPrototype = {
  153. Object: {
  154. defineProperty: Object.defineProperty,
  155. },
  156. };
  157.  
  158. class DOMUtilsEvent {
  159. on(element, eventType, selector, callback, option) {
  160. /**
  161. * 获取option配置
  162. * @param args
  163. * @param startIndex
  164. * @param option
  165. */
  166. function getOption(args, startIndex, option) {
  167. if (typeof args[startIndex] === "boolean") {
  168. option.capture = args[startIndex];
  169. if (typeof args[startIndex + 1] === "boolean") {
  170. option.once = args[startIndex + 1];
  171. }
  172. if (typeof args[startIndex + 2] === "boolean") {
  173. option.passive = args[startIndex + 2];
  174. }
  175. }
  176. else if (typeof args[startIndex] === "object" &&
  177. ("capture" in args[startIndex] ||
  178. "once" in args[startIndex] ||
  179. "passive" in args[startIndex])) {
  180. option.capture = args[startIndex].capture;
  181. option.once = args[startIndex].once;
  182. option.passive = args[startIndex].passive;
  183. }
  184. return option;
  185. }
  186. let DOMUtilsContext = this;
  187. let args = arguments;
  188. if (typeof element === "string") {
  189. element = DOMUtilsCore.document.querySelectorAll(element);
  190. }
  191. if (element == null) {
  192. return;
  193. }
  194. let elementList = [];
  195. if (element instanceof NodeList || Array.isArray(element)) {
  196. element = element;
  197. elementList = [...element];
  198. }
  199. else {
  200. elementList.push(element);
  201. }
  202. let eventTypeList = [];
  203. if (Array.isArray(eventType)) {
  204. eventTypeList = eventTypeList.concat(eventType);
  205. }
  206. else if (typeof eventType === "string") {
  207. eventTypeList = eventTypeList.concat(eventType.split(" "));
  208. }
  209. let _selector_ = selector;
  210. let _callback_ = callback;
  211. let _option_ = {
  212. capture: false,
  213. once: false,
  214. passive: false,
  215. };
  216. if (typeof selector === "function") {
  217. /* 这是为没有selector的情况 */
  218. _selector_ = void 0;
  219. _callback_ = selector;
  220. _option_ = getOption(args, 3, _option_);
  221. }
  222. else {
  223. /* 这是存在selector的情况 */
  224. _option_ = getOption(args, 4, _option_);
  225. }
  226. /**
  227. * 如果是once,那么删除该监听和元素上的事件和监听
  228. */
  229. function checkOptionOnceToRemoveEventListener() {
  230. if (_option_.once) {
  231. DOMUtilsContext.off(element, eventType, selector, callback, option);
  232. }
  233. }
  234. elementList.forEach((elementItem) => {
  235. function ownCallBack(event) {
  236. let target = event.target;
  237. if (_selector_) {
  238. /* 存在自定义子元素选择器 */
  239. let totalParent = DOMUtilsCommonUtils.isWin(elementItem)
  240. ? DOMUtilsCore.document.documentElement
  241. : elementItem;
  242. if (target.matches(_selector_)) {
  243. /* 当前目标可以被selector所匹配到 */
  244. _callback_.call(target, event);
  245. checkOptionOnceToRemoveEventListener();
  246. }
  247. else if (target.closest(_selector_) &&
  248. totalParent.contains(target.closest(_selector_))) {
  249. /* 在上层与主元素之间寻找可以被selector所匹配到的 */
  250. let closestElement = target.closest(_selector_);
  251. /* event的target值不能直接修改 */
  252. OriginPrototype.Object.defineProperty(event, "target", {
  253. get() {
  254. return closestElement;
  255. },
  256. });
  257. _callback_.call(closestElement, event);
  258. checkOptionOnceToRemoveEventListener();
  259. }
  260. }
  261. else {
  262. _callback_.call(elementItem, event);
  263. checkOptionOnceToRemoveEventListener();
  264. }
  265. }
  266. /* 遍历事件名设置元素事件 */
  267. eventTypeList.forEach((eventName) => {
  268. elementItem.addEventListener(eventName, ownCallBack, _option_);
  269. if (_callback_ && _callback_.delegate) {
  270. elementItem.setAttribute("data-delegate", _selector_);
  271. }
  272. /* 获取对象上的事件 */
  273. let elementEvents = elementItem[DOMUtilsData.SymbolEvents] || {};
  274. /* 初始化对象上的xx事件 */
  275. elementEvents[eventName] = elementEvents[eventName] || [];
  276. elementEvents[eventName].push({
  277. selector: _selector_,
  278. option: _option_,
  279. callback: ownCallBack,
  280. originCallBack: _callback_,
  281. });
  282. /* 覆盖事件 */
  283. elementItem[DOMUtilsData.SymbolEvents] = elementEvents;
  284. });
  285. });
  286. }
  287. off(element, eventType, selector, callback, option, filter) {
  288. /**
  289. * 获取option配置
  290. * @param args1
  291. * @param startIndex
  292. * @param option
  293. */
  294. function getOption(args1, startIndex, option) {
  295. if (typeof args1[startIndex] === "boolean") {
  296. option.capture = args1[startIndex];
  297. }
  298. else if (typeof args1[startIndex] === "object" &&
  299. "capture" in args1[startIndex]) {
  300. option.capture = args1[startIndex].capture;
  301. }
  302. return option;
  303. }
  304. let args = arguments;
  305. if (typeof element === "string") {
  306. element = DOMUtilsCore.document.querySelectorAll(element);
  307. }
  308. if (element == null) {
  309. return;
  310. }
  311. let elementList = [];
  312. if (element instanceof NodeList || Array.isArray(element)) {
  313. element = element;
  314. elementList = [...element];
  315. }
  316. else {
  317. elementList.push(element);
  318. }
  319. let eventTypeList = [];
  320. if (Array.isArray(eventType)) {
  321. eventTypeList = eventTypeList.concat(eventType);
  322. }
  323. else if (typeof eventType === "string") {
  324. eventTypeList = eventTypeList.concat(eventType.split(" "));
  325. }
  326. /**
  327. * 子元素选择器
  328. */
  329. let _selector_ = selector;
  330. /**
  331. * 事件的回调函数
  332. */
  333. let _callback_ = callback;
  334. /**
  335. * 事件的配置
  336. */
  337. let _option_ = {
  338. capture: false,
  339. };
  340. if (typeof selector === "function") {
  341. /* 这是为没有selector的情况 */
  342. _selector_ = void 0;
  343. _callback_ = selector;
  344. _option_ = getOption(args, 3, _option_);
  345. }
  346. else {
  347. _option_ = getOption(args, 4, _option_);
  348. }
  349. elementList.forEach((elementItem) => {
  350. /* 获取对象上的事件 */
  351. let elementEvents = elementItem[DOMUtilsData.SymbolEvents] || {};
  352. eventTypeList.forEach((eventName) => {
  353. let handlers = elementEvents[eventName] || [];
  354. if (typeof filter === "function") {
  355. handlers = handlers.filter(filter);
  356. }
  357. for (let index = 0; index < handlers.length; index++) {
  358. let handler = handlers[index];
  359. let flag = false;
  360. if (!_selector_ || handler.selector === _selector_) {
  361. /* selector不为空,进行selector判断 */
  362. flag = true;
  363. }
  364. if (!_callback_ ||
  365. handler.callback === _callback_ ||
  366. handler.originCallBack === _callback_) {
  367. /* callback不为空,进行callback判断 */
  368. flag = true;
  369. }
  370. if (flag) {
  371. elementItem.removeEventListener(eventName, handler.callback, _option_);
  372. handlers.splice(index--, 1);
  373. }
  374. }
  375. if (handlers.length === 0) {
  376. /* 如果没有任意的handler,那么删除该属性 */
  377. DOMUtilsCommonUtils.delete(elementEvents, eventType);
  378. }
  379. });
  380. elementItem[DOMUtilsData.SymbolEvents] = elementEvents;
  381. });
  382. }
  383. /**
  384. * 取消绑定所有的事件
  385. * @param element 需要取消绑定的元素|元素数组
  386. * @param eventType (可选)需要取消监听的事件
  387. */
  388. offAll(element, eventType) {
  389. if (typeof element === "string") {
  390. element = DOMUtilsCore.document.querySelectorAll(element);
  391. }
  392. if (element == null) {
  393. return;
  394. }
  395. let elementList = [];
  396. if (element instanceof NodeList || Array.isArray(element)) {
  397. elementList = [...element];
  398. }
  399. else {
  400. elementList.push(element);
  401. }
  402. let eventTypeList = [];
  403. if (Array.isArray(eventType)) {
  404. eventTypeList = eventTypeList.concat(eventType);
  405. }
  406. else if (typeof eventType === "string") {
  407. eventTypeList = eventTypeList.concat(eventType.split(" "));
  408. }
  409. elementList.forEach((elementItem) => {
  410. Object.getOwnPropertySymbols(elementItem).forEach((symbolEvents) => {
  411. if (!symbolEvents.toString().startsWith("Symbol(events_")) {
  412. return;
  413. }
  414. let elementEvents = elementItem[symbolEvents] || {};
  415. let iterEventNameList = eventTypeList.length
  416. ? eventTypeList
  417. : Object.keys(elementEvents);
  418. iterEventNameList.forEach((eventName) => {
  419. let handlers = elementEvents[eventName];
  420. if (!handlers) {
  421. return;
  422. }
  423. for (const handler of handlers) {
  424. elementItem.removeEventListener(eventName, handler.callback, {
  425. capture: handler["option"]["capture"],
  426. });
  427. }
  428. DOMUtilsCommonUtils.delete(elementItem[symbolEvents], eventName);
  429. });
  430. });
  431. });
  432. }
  433. /**
  434. * 等待文档加载完成后执行指定的函数
  435. * @param callback 需要执行的函数
  436. * @example
  437. * DOMUtils.ready(function(){
  438. * console.log("文档加载完毕")
  439. * })
  440. */
  441. ready(callback) {
  442. if (typeof callback !== "function") {
  443. return;
  444. }
  445. /**
  446. * 检测文档是否加载完毕
  447. */
  448. function checkDOMReadyState() {
  449. try {
  450. if (document.readyState === "complete" ||
  451. (document.readyState !== "loading" &&
  452. !document.documentElement.doScroll)) {
  453. return true;
  454. }
  455. else {
  456. return false;
  457. }
  458. }
  459. catch (error) {
  460. return false;
  461. }
  462. }
  463. /**
  464. * 成功加载完毕后触发的回调函数
  465. */
  466. function completed() {
  467. removeDomReadyListener();
  468. callback();
  469. }
  470. let targetList = [
  471. {
  472. target: DOMUtilsCore.document,
  473. eventType: "DOMContentLoaded",
  474. callback: completed,
  475. },
  476. {
  477. target: DOMUtilsCore.window,
  478. eventType: "load",
  479. callback: completed,
  480. },
  481. ];
  482. /**
  483. * 添加监听
  484. */
  485. function addDomReadyListener() {
  486. for (let index = 0; index < targetList.length; index++) {
  487. let item = targetList[index];
  488. item.target.addEventListener(item.eventType, item.callback);
  489. }
  490. }
  491. /**
  492. * 移除监听
  493. */
  494. function removeDomReadyListener() {
  495. for (let index = 0; index < targetList.length; index++) {
  496. let item = targetList[index];
  497. item.target.removeEventListener(item.eventType, item.callback);
  498. }
  499. }
  500. if (checkDOMReadyState()) {
  501. /* 检查document状态 */
  502. setTimeout(callback);
  503. }
  504. else {
  505. /* 添加监听 */
  506. addDomReadyListener();
  507. }
  508. }
  509. /**
  510. * 主动触发事件
  511. * @param element 需要触发的元素|元素数组|window
  512. * @param eventType 需要触发的事件
  513. * @param details 赋予触发的Event的额外属性,如果是Event类型,那么将自动代替默认new的Event对象
  514. * @param useDispatchToTriggerEvent 是否使用dispatchEvent来触发事件,默认true
  515. * @example
  516. * // 触发元素a.xx的click事件
  517. * DOMUtils.trigger(document.querySelector("a.xx"),"click")
  518. * DOMUtils.trigger("a.xx","click")
  519. * // 触发元素a.xx的click、tap、hover事件
  520. * DOMUtils.trigger(document.querySelector("a.xx"),"click tap hover")
  521. * DOMUtils.trigger("a.xx",["click","tap","hover"])
  522. */
  523. trigger(element, eventType, details, useDispatchToTriggerEvent = true) {
  524. if (typeof element === "string") {
  525. element = DOMUtilsCore.document.querySelector(element);
  526. }
  527. if (element == null) {
  528. return;
  529. }
  530. let elementList = [];
  531. if (element instanceof NodeList || Array.isArray(element)) {
  532. element = element;
  533. elementList = [...element];
  534. }
  535. else {
  536. elementList = [element];
  537. }
  538. let eventTypeList = [];
  539. if (Array.isArray(eventType)) {
  540. eventTypeList = eventType;
  541. }
  542. else if (typeof eventType === "string") {
  543. eventTypeList = eventType.split(" ");
  544. }
  545. elementList.forEach((elementItem) => {
  546. /* 获取对象上的事件 */
  547. let events = elementItem[DOMUtilsData.SymbolEvents] || {};
  548. eventTypeList.forEach((_eventType_) => {
  549. let event = null;
  550. if (details && details instanceof Event) {
  551. event = details;
  552. }
  553. else {
  554. event = new Event(_eventType_);
  555. if (details) {
  556. Object.keys(details).forEach((keyName) => {
  557. event[keyName] = details[keyName];
  558. });
  559. }
  560. }
  561. if (useDispatchToTriggerEvent == false && _eventType_ in events) {
  562. events[_eventType_].forEach((eventsItem) => {
  563. eventsItem.callback(event);
  564. });
  565. }
  566. else {
  567. elementItem.dispatchEvent(event);
  568. }
  569. });
  570. });
  571. }
  572. /**
  573. * 绑定或触发元素的click事件
  574. * @param element 目标元素
  575. * @param handler (可选)事件处理函数
  576. * @param details (可选)赋予触发的Event的额外属性
  577. * @param useDispatchToTriggerEvent (可选)是否使用dispatchEvent来触发事件,默认true
  578. * @example
  579. * // 触发元素a.xx的click事件
  580. * DOMUtils.click(document.querySelector("a.xx"))
  581. * DOMUtils.click("a.xx")
  582. * DOMUtils.click("a.xx",function(){
  583. * console.log("触发click事件成功")
  584. * })
  585. * */
  586. click(element, handler, details, useDispatchToTriggerEvent) {
  587. let DOMUtilsContext = this;
  588. if (typeof element === "string") {
  589. element = DOMUtilsCore.document.querySelector(element);
  590. }
  591. if (element == null) {
  592. return;
  593. }
  594. if (handler == null) {
  595. DOMUtilsContext.trigger(element, "click", details, useDispatchToTriggerEvent);
  596. }
  597. else {
  598. DOMUtilsContext.on(element, "click", null, handler);
  599. }
  600. }
  601. /**
  602. * 绑定或触发元素的blur事件
  603. * @param element 目标元素
  604. * @param handler (可选)事件处理函数
  605. * @param details (可选)赋予触发的Event的额外属性
  606. * @param useDispatchToTriggerEvent (可选)是否使用dispatchEvent来触发事件,默认true
  607. * @example
  608. * // 触发元素a.xx的blur事件
  609. * DOMUtils.blur(document.querySelector("a.xx"))
  610. * DOMUtils.blur("a.xx")
  611. * DOMUtils.blur("a.xx",function(){
  612. * console.log("触发blur事件成功")
  613. * })
  614. * */
  615. blur(element, handler, details, useDispatchToTriggerEvent) {
  616. let DOMUtilsContext = this;
  617. if (typeof element === "string") {
  618. element = DOMUtilsCore.document.querySelector(element);
  619. }
  620. if (element == null) {
  621. return;
  622. }
  623. if (handler === null) {
  624. DOMUtilsContext.trigger(element, "blur", details, useDispatchToTriggerEvent);
  625. }
  626. else {
  627. DOMUtilsContext.on(element, "blur", null, handler);
  628. }
  629. }
  630. /**
  631. * 绑定或触发元素的focus事件
  632. * @param element 目标元素
  633. * @param handler (可选)事件处理函数
  634. * @param details (可选)赋予触发的Event的额外属性
  635. * @param useDispatchToTriggerEvent (可选)是否使用dispatchEvent来触发事件,默认true
  636. * @example
  637. * // 触发元素a.xx的focus事件
  638. * DOMUtils.focus(document.querySelector("a.xx"))
  639. * DOMUtils.focus("a.xx")
  640. * DOMUtils.focus("a.xx",function(){
  641. * console.log("触发focus事件成功")
  642. * })
  643. * */
  644. focus(element, handler, details, useDispatchToTriggerEvent) {
  645. let DOMUtilsContext = this;
  646. if (typeof element === "string") {
  647. element = DOMUtilsCore.document.querySelector(element);
  648. }
  649. if (element == null) {
  650. return;
  651. }
  652. if (handler == null) {
  653. DOMUtilsContext.trigger(element, "focus", details, useDispatchToTriggerEvent);
  654. }
  655. else {
  656. DOMUtilsContext.on(element, "focus", null, handler);
  657. }
  658. }
  659. /**
  660. * 当鼠标移入或移出元素时触发事件
  661. * @param element 当前元素
  662. * @param handler 事件处理函数
  663. * @param option 配置
  664. * @example
  665. * // 监听a.xx元素的移入或移出
  666. * DOMUtils.hover(document.querySelector("a.xx"),()=>{
  667. * console.log("移入/移除");
  668. * })
  669. * DOMUtils.hover("a.xx",()=>{
  670. * console.log("移入/移除");
  671. * })
  672. */
  673. hover(element, handler, option) {
  674. let DOMUtilsContext = this;
  675. if (typeof element === "string") {
  676. element = DOMUtilsCore.document.querySelector(element);
  677. }
  678. if (element == null) {
  679. return;
  680. }
  681. DOMUtilsContext.on(element, "mouseenter", null, handler, option);
  682. DOMUtilsContext.on(element, "mouseleave", null, handler, option);
  683. }
  684. /**
  685. * 当按键松开时触发事件
  686. * keydown - > keypress - > keyup
  687. * @param target 当前元素
  688. * @param handler 事件处理函数
  689. * @param option 配置
  690. * @example
  691. * // 监听a.xx元素的按键松开
  692. * DOMUtils.keyup(document.querySelector("a.xx"),()=>{
  693. * console.log("按键松开");
  694. * })
  695. * DOMUtils.keyup("a.xx",()=>{
  696. * console.log("按键松开");
  697. * })
  698. */
  699. keyup(target, handler, option) {
  700. let DOMUtilsContext = this;
  701. if (target == null) {
  702. return;
  703. }
  704. if (typeof target === "string") {
  705. target = DOMUtilsCore.document.querySelector(target);
  706. }
  707. DOMUtilsContext.on(target, "keyup", null, handler, option);
  708. }
  709. /**
  710. * 当按键按下时触发事件
  711. * keydown - > keypress - > keyup
  712. * @param target 目标
  713. * @param handler 事件处理函数
  714. * @param option 配置
  715. * @example
  716. * // 监听a.xx元素的按键按下
  717. * DOMUtils.keydown(document.querySelector("a.xx"),()=>{
  718. * console.log("按键按下");
  719. * })
  720. * DOMUtils.keydown("a.xx",()=>{
  721. * console.log("按键按下");
  722. * })
  723. */
  724. keydown(target, handler, option) {
  725. let DOMUtilsContext = this;
  726. if (target == null) {
  727. return;
  728. }
  729. if (typeof target === "string") {
  730. target = DOMUtilsCore.document.querySelector(target);
  731. }
  732. DOMUtilsContext.on(target, "keydown", null, handler, option);
  733. }
  734. /**
  735. * 当按键按下时触发事件
  736. * keydown - > keypress - > keyup
  737. * @param target 目标
  738. * @param handler 事件处理函数
  739. * @param option 配置
  740. * @example
  741. * // 监听a.xx元素的按键按下
  742. * DOMUtils.keypress(document.querySelector("a.xx"),()=>{
  743. * console.log("按键按下");
  744. * })
  745. * DOMUtils.keypress("a.xx",()=>{
  746. * console.log("按键按下");
  747. * })
  748. */
  749. keypress(target, handler, option) {
  750. let DOMUtilsContext = this;
  751. if (target == null) {
  752. return;
  753. }
  754. if (typeof target === "string") {
  755. target = DOMUtilsCore.document.querySelector(target);
  756. }
  757. DOMUtilsContext.on(target, "keypress", null, handler, option);
  758. }
  759. }
  760.  
  761. class DOMUtils extends DOMUtilsEvent {
  762. constructor(option) {
  763. DOMUtilsCore.init(option);
  764. super();
  765. }
  766. /** 版本号 */
  767. version = "2024.6.21";
  768. attr(element, attrName, attrValue) {
  769. if (typeof element === "string") {
  770. element = DOMUtilsCore.document.querySelector(element);
  771. }
  772. if (element == null) {
  773. return;
  774. }
  775. if (attrValue == null) {
  776. return element.getAttribute(attrName);
  777. }
  778. else {
  779. element.setAttribute(attrName, attrValue);
  780. }
  781. }
  782. /**
  783. * 创建元素
  784. * @param tagName 标签名
  785. * @param property 属性
  786. * @param attributes 元素上的自定义属性
  787. * @example
  788. * // 创建一个DIV元素,且属性class为xxx
  789. * DOMUtils.createElement("div",undefined,{ class:"xxx" });
  790. * > <div class="xxx"></div>
  791. * @example
  792. * // 创建一个DIV元素
  793. * DOMUtils.createElement("div");
  794. * > <div></div>
  795. * @example
  796. * // 创建一个DIV元素
  797. * DOMUtils.createElement("div","测试");
  798. * > <div>测试</div>
  799. */
  800. createElement(
  801. /** 元素名 */
  802. tagName,
  803. /** 属性 */
  804. property,
  805. /** 自定义属性 */
  806. attributes) {
  807. let tempElement = DOMUtilsCore.document.createElement(tagName);
  808. if (typeof property === "string") {
  809. tempElement.innerHTML = property;
  810. return tempElement;
  811. }
  812. if (property == null) {
  813. property = {};
  814. }
  815. if (attributes == null) {
  816. attributes = {};
  817. }
  818. Object.keys(property).forEach((key) => {
  819. let value = property[key];
  820. tempElement[key] = value;
  821. });
  822. Object.keys(attributes).forEach((key) => {
  823. let value = attributes[key];
  824. if (typeof value === "object") {
  825. /* object转字符串 */
  826. value = JSON.stringify(value);
  827. }
  828. else if (typeof value === "function") {
  829. /* function转字符串 */
  830. value = value.toString();
  831. }
  832. tempElement.setAttribute(key, value);
  833. });
  834. return tempElement;
  835. }
  836. css(element, property, value) {
  837. /**
  838. * 把纯数字没有px的加上
  839. */
  840. function handlePixe(propertyName, propertyValue) {
  841. let allowAddPixe = [
  842. "width",
  843. "height",
  844. "top",
  845. "left",
  846. "right",
  847. "bottom",
  848. "font-size",
  849. ];
  850. if (typeof propertyValue === "number") {
  851. propertyValue = propertyValue.toString();
  852. }
  853. if (typeof propertyValue === "string" &&
  854. allowAddPixe.includes(propertyName) &&
  855. propertyValue.match(/[0-9]$/gi)) {
  856. propertyValue = propertyValue + "px";
  857. }
  858. return propertyValue;
  859. }
  860. if (typeof element === "string") {
  861. element = DOMUtilsCore.document.querySelector(element);
  862. }
  863. if (element == null) {
  864. return;
  865. }
  866. if (typeof property === "string") {
  867. if (value == null) {
  868. return getComputedStyle(element).getPropertyValue(property);
  869. }
  870. else {
  871. if (value === "string" && value.includes("!important")) {
  872. element.style.setProperty(property, value, "important");
  873. }
  874. else {
  875. value = handlePixe(property, value);
  876. element.style.setProperty(property, value);
  877. }
  878. }
  879. }
  880. else if (typeof property === "object") {
  881. for (let prop in property) {
  882. if (typeof property[prop] === "string" &&
  883. property[prop].includes("!important")) {
  884. element.style.setProperty(prop, property[prop], "important");
  885. }
  886. else {
  887. property[prop] = handlePixe(prop, property[prop]);
  888. element.style.setProperty(prop, property[prop]);
  889. }
  890. }
  891. }
  892. }
  893. text(element, text) {
  894. if (typeof element === "string") {
  895. element = DOMUtilsCore.document.querySelector(element);
  896. }
  897. if (element == null) {
  898. return;
  899. }
  900. if (text == null) {
  901. return element.textContent || element.innerText;
  902. }
  903. else {
  904. if (text instanceof Node) {
  905. text = text.textContent || text.innerText;
  906. }
  907. if ("textContent" in element) {
  908. element.textContent = text;
  909. }
  910. else if ("innerText" in element) {
  911. element.innerText = text;
  912. }
  913. }
  914. }
  915. html(element, html) {
  916. if (typeof element === "string") {
  917. element = DOMUtilsCore.document.querySelector(element);
  918. }
  919. if (element == null) {
  920. return;
  921. }
  922. if (html == null) {
  923. return element.innerHTML;
  924. }
  925. else {
  926. if (html instanceof Node) {
  927. html = html.innerHTML;
  928. }
  929. if ("innerHTML" in element) {
  930. element.innerHTML = html;
  931. }
  932. }
  933. }
  934. /**
  935. * 获取移动元素的transform偏移
  936. */
  937. getTransform(element, isShow = false) {
  938. let DOMUtilsContext = this;
  939. let transform_left = 0;
  940. let transform_top = 0;
  941. if (!(isShow || (!isShow && DOMUtilsCommonUtils.isShow(element)))) {
  942. /* 未显示 */
  943. let { recovery } = DOMUtilsCommonUtils.showElement(element);
  944. let transformInfo = DOMUtilsContext.getTransform(element, true);
  945. recovery();
  946. return transformInfo;
  947. }
  948. let elementTransform = getComputedStyle(element).transform;
  949. if (elementTransform != null &&
  950. elementTransform !== "none" &&
  951. elementTransform !== "") {
  952. let elementTransformSplit = elementTransform
  953. .match(/\((.+)\)/)?.[1]
  954. .split(",");
  955. if (elementTransformSplit) {
  956. transform_left = Math.abs(parseInt(elementTransformSplit[4]));
  957. transform_top = Math.abs(parseInt(elementTransformSplit[5]));
  958. }
  959. else {
  960. transform_left = 0;
  961. transform_top = 0;
  962. }
  963. }
  964. return {
  965. transformLeft: transform_left,
  966. transformTop: transform_top,
  967. };
  968. }
  969. val(element, value) {
  970. if (typeof element === "string") {
  971. element = DOMUtilsCore.document.querySelector(element);
  972. }
  973. if (element == null) {
  974. return;
  975. }
  976. if (value == null) {
  977. if (element.localName === "input" &&
  978. (element.type === "checkbox" || element.type === "radio")) {
  979. return element.checked;
  980. }
  981. else {
  982. return element.value;
  983. }
  984. }
  985. else {
  986. if (element.localName === "input" &&
  987. (element.type === "checkbox" || element.type === "radio")) {
  988. element.checked = !!value;
  989. }
  990. else {
  991. element.value = value;
  992. }
  993. }
  994. }
  995. prop(element, propName, propValue) {
  996. if (element == null) {
  997. return;
  998. }
  999. if (typeof element === "string") {
  1000. element = DOMUtilsCore.document.querySelector(element);
  1001. }
  1002. if (propValue == null) {
  1003. return element[propName];
  1004. }
  1005. else {
  1006. element[propName] = propValue;
  1007. }
  1008. }
  1009. /**
  1010. * 移除元素的属性
  1011. * @param element 目标元素
  1012. * @param attrName 属性名
  1013. * @example
  1014. * // 移除元素a.xx的属性data-value
  1015. * DOMUtils.removeAttr(document.querySelector("a.xx"),"data-value")
  1016. * DOMUtils.removeAttr("a.xx","data-value")
  1017. * */
  1018. removeAttr(element, attrName) {
  1019. if (typeof element === "string") {
  1020. element = DOMUtilsCore.document.querySelector(element);
  1021. }
  1022. if (element == null) {
  1023. return;
  1024. }
  1025. element.removeAttribute(attrName);
  1026. }
  1027. /**
  1028. * 移除元素class名
  1029. * @param element 目标元素
  1030. * @param className 类名
  1031. * @example
  1032. * // 移除元素a.xx的className为xx
  1033. * DOMUtils.removeClass(document.querySelector("a.xx"),"xx")
  1034. * DOMUtils.removeClass("a.xx","xx")
  1035. */
  1036. removeClass(element, className) {
  1037. if (typeof element === "string") {
  1038. element = DOMUtilsCore.document.querySelector(element);
  1039. }
  1040. if (element == null) {
  1041. return;
  1042. }
  1043. if (className == null) {
  1044. return;
  1045. }
  1046. element.classList.remove(className);
  1047. }
  1048. /**
  1049. * 移除元素的属性
  1050. * @param element 目标元素
  1051. * @param propName 属性名
  1052. * @example
  1053. * // 移除元素a.xx的href属性
  1054. * DOMUtils.removeProp(document.querySelector("a.xx"),"href")
  1055. * DOMUtils.removeProp("a.xx","href")
  1056. * */
  1057. removeProp(element, propName) {
  1058. if (typeof element === "string") {
  1059. element = DOMUtilsCore.document.querySelector(element);
  1060. }
  1061. if (element == null) {
  1062. return;
  1063. }
  1064. DOMUtilsCommonUtils.delete(element, propName);
  1065. }
  1066. /**
  1067. * 将一个元素替换为另一个元素
  1068. * @param element 目标元素
  1069. * @param newElement 新元素
  1070. * @example
  1071. * // 替换元素a.xx为b.xx
  1072. * DOMUtils.replaceWith(document.querySelector("a.xx"),document.querySelector("b.xx"))
  1073. * DOMUtils.replaceWith("a.xx",'<b class="xx"></b>')
  1074. */
  1075. replaceWith(element, newElement) {
  1076. let DOMUtilsContext = this;
  1077. if (typeof element === "string") {
  1078. element = DOMUtilsCore.document.querySelector(element);
  1079. }
  1080. if (element == null) {
  1081. return;
  1082. }
  1083. if (typeof newElement === "string") {
  1084. newElement = DOMUtilsContext.parseHTML(newElement, false, false);
  1085. }
  1086. if (element instanceof NodeList || element instanceof Array) {
  1087. element.forEach((item) => {
  1088. DOMUtilsContext.replaceWith(item, newElement);
  1089. });
  1090. }
  1091. else {
  1092. element.parentElement.replaceChild(newElement, element);
  1093. }
  1094. }
  1095. /**
  1096. * 给元素添加class
  1097. * @param element 目标元素
  1098. * @param className class名
  1099. * @example
  1100. * // 元素a.xx的className添加_vue_
  1101. * DOMUtils.addClass(document.querySelector("a.xx"),"_vue_")
  1102. * DOMUtils.addClass("a.xx","_vue_")
  1103. * */
  1104. addClass(element, className) {
  1105. if (typeof element === "string") {
  1106. element = DOMUtilsCore.document.querySelector(element);
  1107. }
  1108. if (element == null) {
  1109. return;
  1110. }
  1111. element.classList.add(className);
  1112. }
  1113. /**
  1114. * 函数在元素内部末尾添加子元素或HTML字符串
  1115. * @param element 目标元素
  1116. * @param content 子元素或HTML字符串
  1117. * @example
  1118. * // 元素a.xx的内部末尾添加一个元素
  1119. * DOMUtils.append(document.querySelector("a.xx"),document.querySelector("b.xx"))
  1120. * DOMUtils.append("a.xx","'<b class="xx"></b>")
  1121. * */
  1122. append(element, content) {
  1123. if (typeof element === "string") {
  1124. element = DOMUtilsCore.document.querySelector(element);
  1125. }
  1126. if (element == null) {
  1127. return;
  1128. }
  1129. function elementAppendChild(ele, text) {
  1130. if (typeof content === "string") {
  1131. ele.insertAdjacentHTML("beforeend", text);
  1132. }
  1133. else {
  1134. ele.appendChild(text);
  1135. }
  1136. }
  1137. if (Array.isArray(content) || content instanceof NodeList) {
  1138. /* 数组 */
  1139. let fragment = DOMUtilsCore.document.createDocumentFragment();
  1140. content.forEach((ele) => {
  1141. if (typeof ele === "string") {
  1142. ele = this.parseHTML(ele, true, false);
  1143. }
  1144. fragment.appendChild(ele);
  1145. });
  1146. element.appendChild(fragment);
  1147. }
  1148. else {
  1149. elementAppendChild(element, content);
  1150. }
  1151. }
  1152. /**
  1153. * 函数 在元素内部开头添加子元素或HTML字符串
  1154. * @param element 目标元素
  1155. * @param content 子元素或HTML字符串
  1156. * @example
  1157. * // 元素a.xx内部开头添加一个元素
  1158. * DOMUtils.prepend(document.querySelector("a.xx"),document.querySelector("b.xx"))
  1159. * DOMUtils.prepend("a.xx","'<b class="xx"></b>")
  1160. * */
  1161. prepend(element, content) {
  1162. if (typeof element === "string") {
  1163. element = DOMUtilsCore.document.querySelector(element);
  1164. }
  1165. if (element == null) {
  1166. return;
  1167. }
  1168. if (typeof content === "string") {
  1169. element.insertAdjacentHTML("afterbegin", content);
  1170. }
  1171. else {
  1172. element.insertBefore(content, element.firstChild);
  1173. }
  1174. }
  1175. /**
  1176. * 在元素后面添加兄弟元素或HTML字符串
  1177. * @param element 目标元素
  1178. * @param content 兄弟元素或HTML字符串
  1179. * @example
  1180. * // 元素a.xx后面添加一个元素
  1181. * DOMUtils.after(document.querySelector("a.xx"),document.querySelector("b.xx"))
  1182. * DOMUtils.after("a.xx","'<b class="xx"></b>")
  1183. * */
  1184. after(element, content) {
  1185. if (typeof element === "string") {
  1186. element = DOMUtilsCore.document.querySelector(element);
  1187. }
  1188. if (element == null) {
  1189. return;
  1190. }
  1191. if (typeof content === "string") {
  1192. element.insertAdjacentHTML("afterend", content);
  1193. }
  1194. else {
  1195. element.parentElement.insertBefore(content, element.nextSibling);
  1196. }
  1197. }
  1198. /**
  1199. * 在元素前面添加兄弟元素或HTML字符串
  1200. * @param element 目标元素
  1201. * @param content 兄弟元素或HTML字符串
  1202. * @example
  1203. * // 元素a.xx前面添加一个元素
  1204. * DOMUtils.before(document.querySelector("a.xx"),document.querySelector("b.xx"))
  1205. * DOMUtils.before("a.xx","'<b class="xx"></b>")
  1206. * */
  1207. before(element, content) {
  1208. if (typeof element === "string") {
  1209. element = DOMUtilsCore.document.querySelector(element);
  1210. }
  1211. if (element == null) {
  1212. return;
  1213. }
  1214. if (typeof content === "string") {
  1215. element.insertAdjacentHTML("beforebegin", content);
  1216. }
  1217. else {
  1218. element.parentElement.insertBefore(content, element);
  1219. }
  1220. }
  1221. /**
  1222. * 移除元素
  1223. * @param target 目标元素
  1224. * @example
  1225. * // 元素a.xx前面添加一个元素
  1226. * DOMUtils.remove(document.querySelector("a.xx"))
  1227. * DOMUtils.remove(document.querySelectorAll("a.xx"))
  1228. * DOMUtils.remove("a.xx")
  1229. * */
  1230. remove(target) {
  1231. let DOMUtilsContext = this;
  1232. if (typeof target === "string") {
  1233. target = DOMUtilsCore.document.querySelectorAll(target);
  1234. }
  1235. if (target == null) {
  1236. return;
  1237. }
  1238. if (target instanceof NodeList || target instanceof Array) {
  1239. target = target;
  1240. for (const element of target) {
  1241. DOMUtilsContext.remove(element);
  1242. }
  1243. }
  1244. else {
  1245. target.remove();
  1246. }
  1247. }
  1248. /**
  1249. * 移除元素的所有子元素
  1250. * @param element 目标元素
  1251. * @example
  1252. * // 移除元素a.xx元素的所有子元素
  1253. * DOMUtils.empty(document.querySelector("a.xx"))
  1254. * DOMUtils.empty("a.xx")
  1255. * */
  1256. empty(element) {
  1257. if (typeof element === "string") {
  1258. element = DOMUtilsCore.document.querySelector(element);
  1259. }
  1260. if (element == null) {
  1261. return;
  1262. }
  1263. element.innerHTML = "";
  1264. }
  1265. /**
  1266. * 获取元素相对于文档的偏移坐标(加上文档的滚动条)
  1267. * @param element 目标元素
  1268. * @example
  1269. * // 获取元素a.xx的对于文档的偏移坐标
  1270. * DOMUtils.offset(document.querySelector("a.xx"))
  1271. * DOMUtils.offset("a.xx")
  1272. * > 0
  1273. */
  1274. offset(element) {
  1275. if (typeof element === "string") {
  1276. element = DOMUtilsCore.document.querySelector(element);
  1277. }
  1278. if (element == null) {
  1279. return;
  1280. }
  1281. let rect = element.getBoundingClientRect();
  1282. return {
  1283. /** y轴偏移 */
  1284. top: rect.top + DOMUtilsCore.globalThis.scrollY,
  1285. /** x轴偏移 */
  1286. left: rect.left + DOMUtilsCore.globalThis.scrollX,
  1287. };
  1288. }
  1289. width(element, isShow = false) {
  1290. let DOMUtilsContext = this;
  1291. if (typeof element === "string") {
  1292. element = DOMUtilsCore.document.querySelector(element);
  1293. }
  1294. if (element == null) {
  1295. return;
  1296. }
  1297. if (DOMUtilsCommonUtils.isWin(element)) {
  1298. return DOMUtilsCore.window.document.documentElement.clientWidth;
  1299. }
  1300. if (element.nodeType === 9) {
  1301. /* Document文档节点 */
  1302. element = element;
  1303. return Math.max(element.body.scrollWidth, element.documentElement.scrollWidth, element.body.offsetWidth, element.documentElement.offsetWidth, element.documentElement.clientWidth);
  1304. }
  1305. if (isShow ||
  1306. (!isShow && DOMUtilsCommonUtils.isShow(element))) {
  1307. /* 已显示 */
  1308. /* 不从style中获取对应的宽度,因为可能使用了class定义了width !important */
  1309. element = element;
  1310. /* 如果element.style.width为空 则从css里面获取是否定义了width信息如果定义了 则读取css里面定义的宽度width */
  1311. if (parseFloat(DOMUtilsCommonUtils.getStyleValue(element, "width").toString()) > 0) {
  1312. return parseFloat(DOMUtilsCommonUtils.getStyleValue(element, "width").toString());
  1313. }
  1314. /* 如果从css里获取到的值不是大于0 可能是auto 则通过offsetWidth来进行计算 */
  1315. if (element.offsetWidth > 0) {
  1316. let borderLeftWidth = DOMUtilsCommonUtils.getStyleValue(element, "borderLeftWidth");
  1317. let borderRightWidth = DOMUtilsCommonUtils.getStyleValue(element, "borderRightWidth");
  1318. let paddingLeft = DOMUtilsCommonUtils.getStyleValue(element, "paddingLeft");
  1319. let paddingRight = DOMUtilsCommonUtils.getStyleValue(element, "paddingRight");
  1320. let backHeight = parseFloat(element.offsetWidth.toString()) -
  1321. parseFloat(borderLeftWidth.toString()) -
  1322. parseFloat(borderRightWidth.toString()) -
  1323. parseFloat(paddingLeft.toString()) -
  1324. parseFloat(paddingRight.toString());
  1325. return parseFloat(backHeight.toString());
  1326. }
  1327. return 0;
  1328. }
  1329. else {
  1330. /* 未显示 */
  1331. element = element;
  1332. let { recovery } = DOMUtilsCommonUtils.showElement(element);
  1333. let width = DOMUtilsContext.width(element, true);
  1334. recovery();
  1335. return width;
  1336. }
  1337. }
  1338. height(element, isShow = false) {
  1339. let DOMUtilsContext = this;
  1340. if (DOMUtilsCommonUtils.isWin(element)) {
  1341. return DOMUtilsCore.window.document.documentElement.clientHeight;
  1342. }
  1343. if (typeof element === "string") {
  1344. element = DOMUtilsCore.document.querySelector(element);
  1345. }
  1346. if (element == null) {
  1347. // @ts-ignore
  1348. return;
  1349. }
  1350. if (element.nodeType === 9) {
  1351. element = element;
  1352. /* Document文档节点 */
  1353. return Math.max(element.body.scrollHeight, element.documentElement.scrollHeight, element.body.offsetHeight, element.documentElement.offsetHeight, element.documentElement.clientHeight);
  1354. }
  1355. if (isShow ||
  1356. (!isShow && DOMUtilsCommonUtils.isShow(element))) {
  1357. element = element;
  1358. /* 已显示 */
  1359. /* 从style中获取对应的高度,因为可能使用了class定义了width !important */
  1360. /* 如果element.style.height为空 则从css里面获取是否定义了height信息如果定义了 则读取css里面定义的高度height */
  1361. if (parseFloat(DOMUtilsCommonUtils.getStyleValue(element, "height").toString()) > 0) {
  1362. return parseFloat(DOMUtilsCommonUtils.getStyleValue(element, "height").toString());
  1363. }
  1364. /* 如果从css里获取到的值不是大于0 可能是auto 则通过offsetHeight来进行计算 */
  1365. if (element.offsetHeight > 0) {
  1366. let borderTopWidth = DOMUtilsCommonUtils.getStyleValue(element, "borderTopWidth");
  1367. let borderBottomWidth = DOMUtilsCommonUtils.getStyleValue(element, "borderBottomWidth");
  1368. let paddingTop = DOMUtilsCommonUtils.getStyleValue(element, "paddingTop");
  1369. let paddingBottom = DOMUtilsCommonUtils.getStyleValue(element, "paddingBottom");
  1370. let backHeight = parseFloat(element.offsetHeight.toString()) -
  1371. parseFloat(borderTopWidth.toString()) -
  1372. parseFloat(borderBottomWidth.toString()) -
  1373. parseFloat(paddingTop.toString()) -
  1374. parseFloat(paddingBottom.toString());
  1375. return parseFloat(backHeight.toString());
  1376. }
  1377. return 0;
  1378. }
  1379. else {
  1380. /* 未显示 */
  1381. element = element;
  1382. let { recovery } = DOMUtilsCommonUtils.showElement(element);
  1383. let height = DOMUtilsContext.height(element, true);
  1384. recovery();
  1385. return height;
  1386. }
  1387. }
  1388. outerWidth(element, isShow = false) {
  1389. let DOMUtilsContext = this;
  1390. if (DOMUtilsCommonUtils.isWin(element)) {
  1391. return DOMUtilsCore.window.innerWidth;
  1392. }
  1393. if (typeof element === "string") {
  1394. element = DOMUtilsCore.document.querySelector(element);
  1395. }
  1396. if (element == null) {
  1397. // @ts-ignore
  1398. return;
  1399. }
  1400. element = element;
  1401. if (isShow || (!isShow && DOMUtilsCommonUtils.isShow(element))) {
  1402. let style = getComputedStyle(element, null);
  1403. let marginLeft = DOMUtilsCommonUtils.getStyleValue(style, "marginLeft");
  1404. let marginRight = DOMUtilsCommonUtils.getStyleValue(style, "marginRight");
  1405. return element.offsetWidth + marginLeft + marginRight;
  1406. }
  1407. else {
  1408. let { recovery } = DOMUtilsCommonUtils.showElement(element);
  1409. let outerWidth = DOMUtilsContext.outerWidth(element, true);
  1410. recovery();
  1411. return outerWidth;
  1412. }
  1413. }
  1414. outerHeight(element, isShow = false) {
  1415. let DOMUtilsContext = this;
  1416. if (DOMUtilsCommonUtils.isWin(element)) {
  1417. return DOMUtilsCore.window.innerHeight;
  1418. }
  1419. if (typeof element === "string") {
  1420. element = DOMUtilsCore.document.querySelector(element);
  1421. }
  1422. if (element == null) {
  1423. // @ts-ignore
  1424. return;
  1425. }
  1426. element = element;
  1427. if (isShow || (!isShow && DOMUtilsCommonUtils.isShow(element))) {
  1428. let style = getComputedStyle(element, null);
  1429. let marginTop = DOMUtilsCommonUtils.getStyleValue(style, "marginTop");
  1430. let marginBottom = DOMUtilsCommonUtils.getStyleValue(style, "marginBottom");
  1431. return element.offsetHeight + marginTop + marginBottom;
  1432. }
  1433. else {
  1434. let { recovery } = DOMUtilsCommonUtils.showElement(element);
  1435. let outerHeight = DOMUtilsContext.outerHeight(element, true);
  1436. recovery();
  1437. return outerHeight;
  1438. }
  1439. }
  1440. /**
  1441. * 在一定时间内改变元素的样式属性,实现动画效果
  1442. * @param element 需要进行动画的元素
  1443. * @param styles 动画结束时元素的样式属性
  1444. * @param duration 动画持续时间,单位为毫秒
  1445. * @param callback 动画结束后执行的函数
  1446. * @example
  1447. * // 监听元素a.xx的从显示变为隐藏
  1448. * DOMUtils.animate(document.querySelector("a.xx"),{ top:100},1000,function(){
  1449. * console.log("已往上位移100px")
  1450. * })
  1451. */
  1452. animate(element, styles, duration = 1000, callback = null) {
  1453. if (typeof element === "string") {
  1454. element = DOMUtilsCore.document.querySelector(element);
  1455. }
  1456. if (element == null) {
  1457. return;
  1458. }
  1459. if (typeof duration !== "number" || duration <= 0) {
  1460. throw new TypeError("duration must be a positive number");
  1461. }
  1462. if (typeof callback !== "function" && callback !== void 0) {
  1463. throw new TypeError("callback must be a function or null");
  1464. }
  1465. if (typeof styles !== "object" || styles === void 0) {
  1466. throw new TypeError("styles must be an object");
  1467. }
  1468. if (Object.keys(styles).length === 0) {
  1469. throw new Error("styles must contain at least one property");
  1470. }
  1471. let start = performance.now();
  1472. let from = {};
  1473. let to = {};
  1474. for (let prop in styles) {
  1475. from[prop] = element.style[prop] || getComputedStyle(element)[prop];
  1476. to[prop] = styles[prop];
  1477. }
  1478. let timer = setInterval(function () {
  1479. let timePassed = performance.now() - start;
  1480. let progress = timePassed / duration;
  1481. if (progress > 1) {
  1482. progress = 1;
  1483. }
  1484. for (let prop in styles) {
  1485. element.style[prop] =
  1486. from[prop] + (to[prop] - from[prop]) * progress + "px";
  1487. }
  1488. if (progress === 1) {
  1489. clearInterval(timer);
  1490. if (callback) {
  1491. callback();
  1492. }
  1493. }
  1494. }, 10);
  1495. }
  1496. /**
  1497. * 将一个元素包裹在指定的HTML元素中
  1498. * @param element 要包裹的元素
  1499. * @param wrapperHTML 要包裹的HTML元素的字符串表示形式
  1500. * @example
  1501. * // 将a.xx元素外面包裹一层div
  1502. * DOMUtils.wrap(document.querySelector("a.xx"),"<div></div>")
  1503. */
  1504. wrap(element, wrapperHTML) {
  1505. if (typeof element === "string") {
  1506. element = DOMUtilsCore.document.querySelector(element);
  1507. }
  1508. if (element == null) {
  1509. return;
  1510. }
  1511. element = element;
  1512. // 创建一个新的div元素,并将wrapperHTML作为其innerHTML
  1513. let wrapper = DOMUtilsCore.document.createElement("div");
  1514. wrapper.innerHTML = wrapperHTML;
  1515. let wrapperFirstChild = wrapper.firstChild;
  1516. // 将要包裹的元素插入目标元素前面
  1517. element.parentElement.insertBefore(wrapperFirstChild, element);
  1518. // 将要包裹的元素移动到wrapper中
  1519. wrapperFirstChild.appendChild(element);
  1520. }
  1521. prev(element) {
  1522. if (typeof element === "string") {
  1523. element = DOMUtilsCore.document.querySelector(element);
  1524. }
  1525. if (element == null) {
  1526. return;
  1527. }
  1528. return element.previousElementSibling;
  1529. }
  1530. next(element) {
  1531. if (typeof element === "string") {
  1532. element = DOMUtilsCore.document.querySelector(element);
  1533. }
  1534. if (element == null) {
  1535. return;
  1536. }
  1537. return element.nextElementSibling;
  1538. }
  1539. /**
  1540. * 取消挂载在window下的DOMUtils并返回DOMUtils
  1541. * @example
  1542. * let DOMUtils = window.DOMUtils.noConflict()
  1543. */
  1544. noConflict() {
  1545. if (DOMUtilsCore.window.DOMUtils) {
  1546. DOMUtilsCommonUtils.delete(window, "DOMUtils");
  1547. }
  1548. DOMUtilsCore.window.DOMUtils = this;
  1549. return this;
  1550. }
  1551. siblings(element) {
  1552. if (typeof element === "string") {
  1553. element = DOMUtilsCore.document.querySelector(element);
  1554. }
  1555. if (element == null) {
  1556. return;
  1557. }
  1558. return Array.from(element.parentElement
  1559. .children).filter((child) => child !== element);
  1560. }
  1561. /**
  1562. * 获取当前元素的父元素
  1563. * @param element 当前元素
  1564. * @returns 父元素
  1565. * @example
  1566. * // 获取a.xx元素的父元素
  1567. * DOMUtils.parent(document.querySelector("a.xx"))
  1568. * DOMUtils.parent("a.xx")
  1569. * > <div ...>....</div>
  1570. */
  1571. parent(element) {
  1572. let DOMUtilsContext = this;
  1573. if (typeof element === "string") {
  1574. element = DOMUtilsCore.document.querySelector(element);
  1575. }
  1576. if (element == null) {
  1577. return;
  1578. }
  1579. if (element instanceof NodeList || element instanceof Array) {
  1580. element = element;
  1581. let resultArray = [];
  1582. element.forEach((eleItem) => {
  1583. resultArray.push(DOMUtilsContext.parent(eleItem));
  1584. });
  1585. return resultArray;
  1586. }
  1587. else {
  1588. return element.parentElement;
  1589. }
  1590. }
  1591. parseHTML(html, useParser = false, isComplete = false) {
  1592. function parseHTMLByDOMParser() {
  1593. let parser = new DOMParser();
  1594. if (isComplete) {
  1595. return parser.parseFromString(html, "text/html");
  1596. }
  1597. else {
  1598. return parser.parseFromString(html, "text/html").body.firstChild;
  1599. }
  1600. }
  1601. function parseHTMLByCreateDom() {
  1602. let tempDIV = DOMUtilsCore.document.createElement("div");
  1603. tempDIV.innerHTML = html;
  1604. if (isComplete) {
  1605. return tempDIV;
  1606. }
  1607. else {
  1608. return tempDIV.firstChild;
  1609. }
  1610. }
  1611. if (useParser) {
  1612. return parseHTMLByDOMParser();
  1613. }
  1614. else {
  1615. return parseHTMLByCreateDom();
  1616. }
  1617. }
  1618. /**
  1619. * 显示元素
  1620. * @param target 当前元素
  1621. * @example
  1622. * // 显示a.xx元素
  1623. * DOMUtils.show(document.querySelector("a.xx"))
  1624. * DOMUtils.show(document.querySelectorAll("a.xx"))
  1625. * DOMUtils.show("a.xx")
  1626. */
  1627. show(target) {
  1628. let DOMUtilsContext = this;
  1629. if (target == null) {
  1630. return;
  1631. }
  1632. if (typeof target === "string") {
  1633. target = DOMUtilsCore.document.querySelectorAll(target);
  1634. }
  1635. if (target instanceof NodeList || target instanceof Array) {
  1636. target = target;
  1637. for (const element of target) {
  1638. DOMUtilsContext.show(element);
  1639. }
  1640. }
  1641. else {
  1642. target = target;
  1643. target.style.display = "";
  1644. if (!DOMUtilsCommonUtils.isShow(target)) {
  1645. /* 仍然是不显示,尝试使用强覆盖 */
  1646. target.style.setProperty("display", "unset", "important");
  1647. }
  1648. }
  1649. }
  1650. /**
  1651. * 隐藏元素
  1652. * @param target 当前元素
  1653. * @example
  1654. * // 隐藏a.xx元素
  1655. * DOMUtils.hide(document.querySelector("a.xx"))
  1656. * DOMUtils.hide(document.querySelectorAll("a.xx"))
  1657. * DOMUtils.hide("a.xx")
  1658. */
  1659. hide(target) {
  1660. let DOMUtilsContext = this;
  1661. if (target == null) {
  1662. return;
  1663. }
  1664. if (typeof target === "string") {
  1665. target = DOMUtilsCore.document.querySelectorAll(target);
  1666. }
  1667. if (target instanceof NodeList || target instanceof Array) {
  1668. target = target;
  1669. for (const element of target) {
  1670. DOMUtilsContext.hide(element);
  1671. }
  1672. }
  1673. else {
  1674. target = target;
  1675. target.style.display = "none";
  1676. if (DOMUtilsCommonUtils.isShow(target)) {
  1677. /* 仍然是显示,尝试使用强覆盖 */
  1678. target.style.setProperty("display", "none", "important");
  1679. }
  1680. }
  1681. }
  1682. /**
  1683. * 淡入元素
  1684. * @param element 当前元素
  1685. * @param duration 动画持续时间(毫秒),默认400毫秒
  1686. * @param callback 动画结束的回调
  1687. * @example
  1688. * // 元素a.xx淡入
  1689. * DOMUtils.fadeIn(document.querySelector("a.xx"),2500,()=>{
  1690. * console.log("淡入完毕");
  1691. * })
  1692. * DOMUtils.fadeIn("a.xx",undefined,()=>{
  1693. * console.log("淡入完毕");
  1694. * })
  1695. */
  1696. fadeIn(element, duration = 400, callback) {
  1697. if (element == null) {
  1698. return;
  1699. }
  1700. if (typeof element === "string") {
  1701. element = DOMUtilsCore.document.querySelector(element);
  1702. }
  1703. element = element;
  1704. element.style.opacity = "0";
  1705. element.style.display = "";
  1706. let start = null;
  1707. let timer = null;
  1708. function step(timestamp) {
  1709. if (!start)
  1710. start = timestamp;
  1711. let progress = timestamp - start;
  1712. element = element;
  1713. element.style.opacity = Math.min(progress / duration, 1).toString();
  1714. if (progress < duration) {
  1715. DOMUtilsCore.window.requestAnimationFrame(step);
  1716. }
  1717. else {
  1718. if (callback && typeof callback === "function") {
  1719. callback();
  1720. }
  1721. DOMUtilsCore.window.cancelAnimationFrame(timer);
  1722. }
  1723. }
  1724. timer = DOMUtilsCore.window.requestAnimationFrame(step);
  1725. }
  1726. /**
  1727. * 淡出元素
  1728. * @param element 当前元素
  1729. * @param duration 动画持续时间(毫秒),默认400毫秒
  1730. * @param callback 动画结束的回调
  1731. * @example
  1732. * // 元素a.xx淡出
  1733. * DOMUtils.fadeOut(document.querySelector("a.xx"),2500,()=>{
  1734. * console.log("淡出完毕");
  1735. * })
  1736. * DOMUtils.fadeOut("a.xx",undefined,()=>{
  1737. * console.log("淡出完毕");
  1738. * })
  1739. */
  1740. fadeOut(element, duration = 400, callback) {
  1741. if (element == null) {
  1742. return;
  1743. }
  1744. if (typeof element === "string") {
  1745. element = DOMUtilsCore.document.querySelector(element);
  1746. }
  1747. element = element;
  1748. element.style.opacity = "1";
  1749. let start = null;
  1750. let timer = null;
  1751. function step(timestamp) {
  1752. if (!start)
  1753. start = timestamp;
  1754. let progress = timestamp - start;
  1755. element = element;
  1756. element.style.opacity = Math.max(1 - progress / duration, 0).toString();
  1757. if (progress < duration) {
  1758. DOMUtilsCore.window.requestAnimationFrame(step);
  1759. }
  1760. else {
  1761. element.style.display = "none";
  1762. if (typeof callback === "function") {
  1763. callback();
  1764. }
  1765. DOMUtilsCore.window.cancelAnimationFrame(timer);
  1766. }
  1767. }
  1768. timer = DOMUtilsCore.window.requestAnimationFrame(step);
  1769. }
  1770. /**
  1771. * 切换元素的显示和隐藏状态
  1772. * @param element 当前元素
  1773. * @example
  1774. * // 如果元素a.xx当前是隐藏,则显示,如果是显示,则隐藏
  1775. * DOMUtils.toggle(document.querySelector("a.xx"))
  1776. * DOMUtils.toggle("a.xx")
  1777. */
  1778. toggle(element) {
  1779. let DOMUtilsContext = this;
  1780. if (typeof element === "string") {
  1781. element = DOMUtilsCore.document.querySelector(element);
  1782. }
  1783. if (element == null) {
  1784. return;
  1785. }
  1786. if (getComputedStyle(element).getPropertyValue("display") === "none") {
  1787. DOMUtilsContext.show(element);
  1788. }
  1789. else {
  1790. DOMUtilsContext.hide(element);
  1791. }
  1792. }
  1793. /**
  1794. * 创建一个新的DOMUtils实例
  1795. * @param option
  1796. * @returns
  1797. */
  1798. createDOMUtils(option) {
  1799. return new DOMUtils(option);
  1800. }
  1801. /**
  1802. * 获取文字的位置信息
  1803. * @param $input 输入框
  1804. * @param selectionStart 起始位置
  1805. * @param selectionEnd 结束位置
  1806. * @example
  1807. * DOMUtils.getTextBoundingRect(document.querySelector("input"));
  1808. */
  1809. getTextBoundingRect($input, selectionStart, selectionEnd) {
  1810. // Basic parameter validation
  1811. if (!$input || !("value" in $input))
  1812. return $input;
  1813. if (selectionStart == null) {
  1814. selectionStart = $input.selectionStart || 0;
  1815. }
  1816. if (selectionEnd == null) {
  1817. selectionEnd = $input.selectionEnd || 0;
  1818. }
  1819. if (typeof selectionStart == "string")
  1820. selectionStart = parseFloat(selectionStart);
  1821. if (typeof selectionStart != "number" || isNaN(selectionStart)) {
  1822. selectionStart = 0;
  1823. }
  1824. if (selectionStart < 0)
  1825. selectionStart = 0;
  1826. else
  1827. selectionStart = Math.min($input.value.length, selectionStart);
  1828. if (typeof selectionEnd == "string")
  1829. selectionEnd = parseFloat(selectionEnd);
  1830. if (typeof selectionEnd != "number" ||
  1831. isNaN(selectionEnd) ||
  1832. selectionEnd < selectionStart) {
  1833. selectionEnd = selectionStart;
  1834. }
  1835. if (selectionEnd < 0)
  1836. selectionEnd = 0;
  1837. else
  1838. selectionEnd = Math.min($input.value.length, selectionEnd);
  1839. // If available (thus IE), use the createTextRange method
  1840. // @ts-ignore
  1841. if (typeof $input.createTextRange == "function") {
  1842. let range = $input.createTextRange();
  1843. range.collapse(true);
  1844. range.moveStart("character", selectionStart);
  1845. range.moveEnd("character", selectionEnd - selectionStart);
  1846. return range.getBoundingClientRect();
  1847. }
  1848. // createTextRange is not supported, create a fake text range
  1849. let offset = getInputOffset(), topPos = offset.top, leftPos = offset.left, width = getInputCSS("width", true), height = getInputCSS("height", true);
  1850. // Styles to simulate a node in an input field
  1851. let cssDefaultStyles = "white-space:pre;padding:0;margin:0;", listOfModifiers = [
  1852. "direction",
  1853. "font-family",
  1854. "font-size",
  1855. "font-size-adjust",
  1856. "font-variant",
  1857. "font-weight",
  1858. "font-style",
  1859. "letter-spacing",
  1860. "line-height",
  1861. "text-align",
  1862. "text-indent",
  1863. "text-transform",
  1864. "word-wrap",
  1865. "word-spacing",
  1866. ];
  1867. topPos += getInputCSS("padding-top", true);
  1868. topPos += getInputCSS("border-top-width", true);
  1869. leftPos += getInputCSS("padding-left", true);
  1870. leftPos += getInputCSS("border-left-width", true);
  1871. leftPos += 1; //Seems to be necessary
  1872. for (let index = 0; index < listOfModifiers.length; index++) {
  1873. let property = listOfModifiers[index];
  1874. // @ts-ignore
  1875. cssDefaultStyles += property + ":" + getInputCSS(property) + ";";
  1876. }
  1877. // End of CSS variable checks
  1878. // 不能为空,不然获取不到高度
  1879. let text = $input.value || "G", textLen = text.length, fakeClone = DOMUtilsCore.document.createElement("div");
  1880. if (selectionStart > 0)
  1881. appendPart(0, selectionStart);
  1882. var fakeRange = appendPart(selectionStart, selectionEnd);
  1883. if (textLen > selectionEnd)
  1884. appendPart(selectionEnd, textLen);
  1885. // Styles to inherit the font styles of the element
  1886. fakeClone.style.cssText = cssDefaultStyles;
  1887. // Styles to position the text node at the desired position
  1888. fakeClone.style.position = "absolute";
  1889. fakeClone.style.top = topPos + "px";
  1890. fakeClone.style.left = leftPos + "px";
  1891. fakeClone.style.width = width + "px";
  1892. fakeClone.style.height = height + "px";
  1893. DOMUtilsCore.document.body.appendChild(fakeClone);
  1894. var returnValue = fakeRange.getBoundingClientRect(); //Get rect
  1895. fakeClone?.parentNode?.removeChild(fakeClone); //Remove temp
  1896. return returnValue;
  1897. // Local functions for readability of the previous code
  1898. /**
  1899. *
  1900. * @param start
  1901. * @param end
  1902. * @returns
  1903. */
  1904. function appendPart(start, end) {
  1905. var span = DOMUtilsCore.document.createElement("span");
  1906. span.style.cssText = cssDefaultStyles; //Force styles to prevent unexpected results
  1907. span.textContent = text.substring(start, end);
  1908. fakeClone.appendChild(span);
  1909. return span;
  1910. }
  1911. // Computing offset position
  1912. function getInputOffset() {
  1913. let body = DOMUtilsCore.document.body, win = DOMUtilsCore.document.defaultView, docElem = DOMUtilsCore.document.documentElement, $box = DOMUtilsCore.document.createElement("div");
  1914. $box.style.paddingLeft = $box.style.width = "1px";
  1915. body.appendChild($box);
  1916. var isBoxModel = $box.offsetWidth == 2;
  1917. body.removeChild($box);
  1918. let $boxRect = $input.getBoundingClientRect();
  1919. var clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, scrollTop = win.pageYOffset ||
  1920. (isBoxModel && docElem.scrollTop) ||
  1921. body.scrollTop, scrollLeft = win.pageXOffset ||
  1922. (isBoxModel && docElem.scrollLeft) ||
  1923. body.scrollLeft;
  1924. return {
  1925. top: $boxRect.top + scrollTop - clientTop,
  1926. left: $boxRect.left + scrollLeft - clientLeft,
  1927. };
  1928. }
  1929. /**
  1930. *
  1931. * @param prop
  1932. * @param isNumber
  1933. * @returns
  1934. */
  1935. function getInputCSS(prop, isNumber) {
  1936. var val = DOMUtilsCore.document
  1937. .defaultView.getComputedStyle($input, null)
  1938. .getPropertyValue(prop);
  1939. return isNumber ? parseFloat(val) : val;
  1940. }
  1941. }
  1942. }
  1943. let domUtils = new DOMUtils();
  1944.  
  1945. return domUtils;
  1946.  
  1947. }));
  1948. //# sourceMappingURL=index.umd.js.map

QingJ © 2025

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