dom.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /* istanbul ignore next */
  2. import Vue from 'vue';
  3. const isServer = Vue.prototype.$isServer;
  4. const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
  5. const MOZ_HACK_REGEXP = /^moz([A-Z])/;
  6. const ieVersion = isServer ? 0 : Number(document.documentMode);
  7. /* istanbul ignore next */
  8. const trim = function(string) {
  9. return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
  10. };
  11. /* istanbul ignore next */
  12. const camelCase = function(name) {
  13. return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
  14. return offset ? letter.toUpperCase() : letter;
  15. }).replace(MOZ_HACK_REGEXP, 'Moz$1');
  16. };
  17. /* istanbul ignore next */
  18. export const on = (function() {
  19. if (!isServer && document.addEventListener) {
  20. return function(element, event, handler) {
  21. if (element && event && handler) {
  22. element.addEventListener(event, handler, false);
  23. }
  24. };
  25. } else {
  26. return function(element, event, handler) {
  27. if (element && event && handler) {
  28. element.attachEvent('on' + event, handler);
  29. }
  30. };
  31. }
  32. })();
  33. /* istanbul ignore next */
  34. export const off = (function() {
  35. if (!isServer && document.removeEventListener) {
  36. return function(element, event, handler) {
  37. if (element && event) {
  38. element.removeEventListener(event, handler, false);
  39. }
  40. };
  41. } else {
  42. return function(element, event, handler) {
  43. if (element && event) {
  44. element.detachEvent('on' + event, handler);
  45. }
  46. };
  47. }
  48. })();
  49. /* istanbul ignore next */
  50. export const once = function(el, event, fn) {
  51. var listener = function() {
  52. if (fn) {
  53. fn.apply(this, arguments);
  54. }
  55. off(el, event, listener);
  56. };
  57. on(el, event, listener);
  58. };
  59. /* istanbul ignore next */
  60. export function hasClass(el, cls) {
  61. if (!el || !cls) return false;
  62. if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
  63. if (el.classList) {
  64. return el.classList.contains(cls);
  65. } else {
  66. return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
  67. }
  68. };
  69. /* istanbul ignore next */
  70. export function addClass(el, cls) {
  71. if (!el) return;
  72. var curClass = el.className;
  73. var classes = (cls || '').split(' ');
  74. for (var i = 0, j = classes.length; i < j; i++) {
  75. var clsName = classes[i];
  76. if (!clsName) continue;
  77. if (el.classList) {
  78. el.classList.add(clsName);
  79. } else if (!hasClass(el, clsName)) {
  80. curClass += ' ' + clsName;
  81. }
  82. }
  83. if (!el.classList) {
  84. el.className = curClass;
  85. }
  86. };
  87. /* istanbul ignore next */
  88. export function removeClass(el, cls) {
  89. if (!el || !cls) return;
  90. var classes = cls.split(' ');
  91. var curClass = ' ' + el.className + ' ';
  92. for (var i = 0, j = classes.length; i < j; i++) {
  93. var clsName = classes[i];
  94. if (!clsName) continue;
  95. if (el.classList) {
  96. el.classList.remove(clsName);
  97. } else if (hasClass(el, clsName)) {
  98. curClass = curClass.replace(' ' + clsName + ' ', ' ');
  99. }
  100. }
  101. if (!el.classList) {
  102. el.className = trim(curClass);
  103. }
  104. };
  105. /* istanbul ignore next */
  106. export const getStyle = ieVersion < 9 ? function(element, styleName) {
  107. if (isServer) return;
  108. if (!element || !styleName) return null;
  109. styleName = camelCase(styleName);
  110. if (styleName === 'float') {
  111. styleName = 'styleFloat';
  112. }
  113. try {
  114. switch (styleName) {
  115. case 'opacity':
  116. try {
  117. return element.filters.item('alpha').opacity / 100;
  118. } catch (e) {
  119. return 1.0;
  120. }
  121. default:
  122. return (element.style[styleName] || element.currentStyle ? element.currentStyle[styleName] : null);
  123. }
  124. } catch (e) {
  125. return element.style[styleName];
  126. }
  127. } : function(element, styleName) {
  128. if (isServer) return;
  129. if (!element || !styleName) return null;
  130. styleName = camelCase(styleName);
  131. if (styleName === 'float') {
  132. styleName = 'cssFloat';
  133. }
  134. try {
  135. var computed = document.defaultView.getComputedStyle(element, '');
  136. return element.style[styleName] || computed ? computed[styleName] : null;
  137. } catch (e) {
  138. return element.style[styleName];
  139. }
  140. };
  141. /* istanbul ignore next */
  142. export function setStyle(element, styleName, value) {
  143. if (!element || !styleName) return;
  144. if (typeof styleName === 'object') {
  145. for (var prop in styleName) {
  146. if (styleName.hasOwnProperty(prop)) {
  147. setStyle(element, prop, styleName[prop]);
  148. }
  149. }
  150. } else {
  151. styleName = camelCase(styleName);
  152. if (styleName === 'opacity' && ieVersion < 9) {
  153. element.style.filter = isNaN(value) ? '' : 'alpha(opacity=' + value * 100 + ')';
  154. } else {
  155. element.style[styleName] = value;
  156. }
  157. }
  158. };
  159. export const isScroll = (el, vertical) => {
  160. if (isServer) return;
  161. const determinedDirection = vertical !== null || vertical !== undefined;
  162. const overflow = determinedDirection
  163. ? vertical
  164. ? getStyle(el, 'overflow-y')
  165. : getStyle(el, 'overflow-x')
  166. : getStyle(el, 'overflow');
  167. return overflow.match(/(scroll|auto)/);
  168. };
  169. export const getScrollContainer = (el, vertical) => {
  170. if (isServer) return;
  171. let parent = el;
  172. while (parent) {
  173. if ([window, document, document.documentElement].includes(parent)) {
  174. return window;
  175. }
  176. if (isScroll(parent, vertical)) {
  177. return parent;
  178. }
  179. parent = parent.parentNode;
  180. }
  181. return parent;
  182. };
  183. export const isInContainer = (el, container) => {
  184. if (isServer || !el || !container) return false;
  185. const elRect = el.getBoundingClientRect();
  186. let containerRect;
  187. if ([window, document, document.documentElement, null, undefined].includes(container)) {
  188. containerRect = {
  189. top: 0,
  190. right: window.innerWidth,
  191. bottom: window.innerHeight,
  192. left: 0
  193. };
  194. } else {
  195. containerRect = container.getBoundingClientRect();
  196. }
  197. return elRect.top < containerRect.bottom &&
  198. elRect.bottom > containerRect.top &&
  199. elRect.right > containerRect.left &&
  200. elRect.left < containerRect.right;
  201. };