dom.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /* == class 相关 == */
  2. const any = (obj: any) => obj;
  3. // 添加 class
  4. export const addClass = (element: Element, ...className: string[]): void => {
  5. element.classList.add(...className);
  6. };
  7. // 移除 class
  8. export const removeClass = (element: Element, ...className: string[]): void => {
  9. element.classList.remove(...className);
  10. };
  11. // 是否包含指定 class
  12. export const hasClass = (element: Element, className: string): boolean => {
  13. return element.classList.contains(className);
  14. };
  15. // 切换指定 class
  16. // 若为移除,则返回 false;若为添加,则返回 true
  17. export const toggleClass = (element: Element, className: string): boolean => {
  18. return element.classList.toggle(className);
  19. };
  20. /* == DOM 相关 == */
  21. // 查找第一个指定的css选择器
  22. export const query = (
  23. startNode: Element,
  24. cssSelector: string
  25. ): Element | null => {
  26. return startNode.querySelector(cssSelector);
  27. };
  28. // 查找所有指定的css选择器
  29. export const queryAll = (
  30. startNode: Element,
  31. cssSelector: string
  32. ): NodeListOf<Element> => {
  33. return (startNode || document).querySelectorAll(cssSelector);
  34. };
  35. // 返回或者设置 innerHTML
  36. // eslint-disable-next-line consistent-return
  37. export const html = (element: Element, innerHTML?: string): string | void => {
  38. if (typeof innerHTML === "undefined") {
  39. return element.innerHTML;
  40. }
  41. element.innerHTML = innerHTML;
  42. };
  43. // 返回或者设置 innerText
  44. // eslint-disable-next-line consistent-return
  45. export const text = (
  46. element: HTMLElement,
  47. innerText?: string
  48. ): string | void => {
  49. if (typeof innerText === "undefined") {
  50. return element.innerText;
  51. }
  52. element.innerText = innerText;
  53. };
  54. // 创建元素
  55. export const createElement = (tagName: string): HTMLElement => {
  56. return document.createElement(tagName);
  57. };
  58. // 在container内部的后面挂载元素
  59. export const append = (container: Element, ...element: Element[]): void => {
  60. container.append(...element);
  61. };
  62. // 在container内部的前面挂载元素
  63. export const prepend = (container: Element, ...element: Element[]): void => {
  64. container.prepend(...element);
  65. };
  66. // 移除元素
  67. export const remove = (element: Element | null): void => {
  68. element && element.remove();
  69. };
  70. // 绑定事件
  71. export const on = (
  72. element: Element,
  73. eventName: string,
  74. callback: (event: Event) => void,
  75. useCapture = false
  76. ): void => {
  77. element.addEventListener(eventName, callback, useCapture);
  78. };
  79. // 解绑事件
  80. export const off = (
  81. element: Element,
  82. eventName: string,
  83. callback: (event: Event) => void
  84. ): void => {
  85. element.removeEventListener(eventName, callback);
  86. };
  87. // hover
  88. export const hover = (
  89. element: Element,
  90. handlerIn: (e: Event) => void,
  91. handlerOut: (e: Event) => void
  92. ): void => {
  93. on(element, "mouseenter", handlerIn);
  94. on(element, "mouseleave", handlerOut);
  95. };
  96. // wheel滚轮事件
  97. export const wheel = (
  98. element: Element,
  99. handlerWheel: (e: Event) => void
  100. ): void => {
  101. on(element, "mousewheel", handlerWheel);
  102. };
  103. // 解析字符串生成DOM元素
  104. export const parse = (innerHTML: string): Element => {
  105. const container = createElement("div");
  106. html(container, innerHTML.trim());
  107. return container.firstChild as Element;
  108. };
  109. // 设置元素样式
  110. export const style = (
  111. element: HTMLElement,
  112. styleObj: { [key in keyof CSSStyleDeclaration]?: string }
  113. ): void => {
  114. const keys = Object.keys(styleObj);
  115. keys.forEach((key) => {
  116. any(element.style)[key] = any(styleObj)[key];
  117. });
  118. };
  119. // 清空dom元素
  120. export const empty = (element: Element): void => {
  121. let child;
  122. // eslint-disable-next-line no-cond-assign
  123. while ((child = element.lastChild)) {
  124. element.removeChild(child);
  125. }
  126. };
  127. // 获取元素的位置
  128. export const getElementOffset = (element: HTMLElement) => {
  129. const offset = { left: 0, top: 0 };
  130. let current: HTMLElement = element.offsetParent as any;
  131. offset.left += element.offsetLeft;
  132. offset.top += element.offsetTop;
  133. while (current !== null) {
  134. offset.left += current.offsetLeft;
  135. offset.top += current.offsetTop;
  136. current = current.offsetParent as any;
  137. }
  138. return offset;
  139. };
  140. /**
  141. * Returns caret position in text input
  142. *
  143. * @author http://stackoverflow.com/questions/263743/how-to-get-caret-position-in-textarea
  144. * @return {Number}
  145. */
  146. export const getCaretPosition = (el: HTMLInputElement) => {
  147. if (el.selectionStart) {
  148. return el.selectionStart;
  149. }
  150. if ((document as any).selection) {
  151. // IE8
  152. el.focus();
  153. const r = (document as any).selection.createRange();
  154. if (r == null) {
  155. return 0;
  156. }
  157. const re = (el as any).createTextRange();
  158. const rc = re.duplicate();
  159. re.moveToBookmark(r.getBookmark());
  160. rc.setEndPoint("EndToStart", re);
  161. return rc.text.length;
  162. }
  163. return 0;
  164. };
  165. /**
  166. * Sets caret position in text input.
  167. *
  168. * @author http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea/
  169. * @param {Element} element
  170. * @param {Number} pos
  171. * @param {Number} endPos
  172. */
  173. export const setCaretPosition = (
  174. element: HTMLInputElement,
  175. pos: number,
  176. endPos: number
  177. ) => {
  178. if (endPos === 0) {
  179. endPos = pos;
  180. }
  181. if (element.setSelectionRange) {
  182. element.focus();
  183. try {
  184. element.setSelectionRange(pos, endPos);
  185. } catch (err) {
  186. const elementParent = element.parentNode as HTMLElement;
  187. const parentDisplayValue = elementParent.style.display;
  188. elementParent.style.display = "block";
  189. element.setSelectionRange(pos, endPos);
  190. elementParent.style.display = parentDisplayValue;
  191. }
  192. } else if ((element as any).createTextRange) {
  193. // IE8
  194. const range = (element as any).createTextRange();
  195. range.collapse(true);
  196. range.moveEnd("character", endPos);
  197. range.moveStart("character", pos);
  198. range.select();
  199. }
  200. };