index.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. 'use strict';
  2. var attrs = ['top', 'left', 'right', 'bottom'];
  3. var inited;
  4. var elementComputedStyle = {};
  5. var support;
  6. function getSupport() {
  7. if (!('CSS' in window) || typeof CSS.supports != 'function') {
  8. support = '';
  9. }
  10. else if (CSS.supports('top: env(safe-area-inset-top)')) {
  11. support = 'env';
  12. }
  13. else if (CSS.supports('top: constant(safe-area-inset-top)')) {
  14. support = 'constant';
  15. }
  16. else {
  17. support = '';
  18. }
  19. return support;
  20. }
  21. function init() {
  22. support = typeof support === 'string' ? support : getSupport();
  23. if (!support) {
  24. attrs.forEach(function (attr) {
  25. elementComputedStyle[attr] = 0;
  26. });
  27. return;
  28. }
  29. function setStyle(el, style) {
  30. var elStyle = el.style;
  31. Object.keys(style).forEach(function (key) {
  32. var val = style[key];
  33. elStyle[key] = val;
  34. });
  35. }
  36. var cbs = [];
  37. function parentReady(callback) {
  38. if (callback) {
  39. cbs.push(callback);
  40. }
  41. else {
  42. cbs.forEach(function (cb) {
  43. cb();
  44. });
  45. }
  46. }
  47. var passiveEvents = false;
  48. try {
  49. var opts = Object.defineProperty({}, 'passive', {
  50. get: function () {
  51. passiveEvents = { passive: true };
  52. }
  53. });
  54. window.addEventListener('test', null, opts);
  55. }
  56. catch (e) {
  57. }
  58. function addChild(parent, attr) {
  59. var a1 = document.createElement('div');
  60. var a2 = document.createElement('div');
  61. var a1Children = document.createElement('div');
  62. var a2Children = document.createElement('div');
  63. var W = 100;
  64. var MAX = 10000;
  65. var aStyle = {
  66. position: 'absolute',
  67. width: W + 'px',
  68. height: '200px',
  69. boxSizing: 'border-box',
  70. overflow: 'hidden',
  71. paddingBottom: support + "(safe-area-inset-" + attr + ")"
  72. };
  73. setStyle(a1, aStyle);
  74. setStyle(a2, aStyle);
  75. setStyle(a1Children, {
  76. transition: '0s',
  77. animation: 'none',
  78. width: '400px',
  79. height: '400px'
  80. });
  81. setStyle(a2Children, {
  82. transition: '0s',
  83. animation: 'none',
  84. width: '250%',
  85. height: '250%'
  86. });
  87. a1.appendChild(a1Children);
  88. a2.appendChild(a2Children);
  89. parent.appendChild(a1);
  90. parent.appendChild(a2);
  91. parentReady(function () {
  92. a1.scrollTop = a2.scrollTop = MAX;
  93. var a1LastScrollTop = a1.scrollTop;
  94. var a2LastScrollTop = a2.scrollTop;
  95. function onScroll() {
  96. if (this.scrollTop === (this === a1 ? a1LastScrollTop : a2LastScrollTop)) {
  97. return;
  98. }
  99. a1.scrollTop = a2.scrollTop = MAX;
  100. a1LastScrollTop = a1.scrollTop;
  101. a2LastScrollTop = a2.scrollTop;
  102. attrChange(attr);
  103. }
  104. a1.addEventListener('scroll', onScroll, passiveEvents);
  105. a2.addEventListener('scroll', onScroll, passiveEvents);
  106. });
  107. var computedStyle = getComputedStyle(a1);
  108. Object.defineProperty(elementComputedStyle, attr, {
  109. configurable: true,
  110. get: function () {
  111. return parseFloat(computedStyle.paddingBottom);
  112. }
  113. });
  114. }
  115. var parentDiv = document.createElement('div');
  116. setStyle(parentDiv, {
  117. position: 'absolute',
  118. left: '0',
  119. top: '0',
  120. width: '0',
  121. height: '0',
  122. zIndex: '-1',
  123. overflow: 'hidden',
  124. visibility: 'hidden',
  125. });
  126. attrs.forEach(function (key) {
  127. addChild(parentDiv, key);
  128. });
  129. document.body.appendChild(parentDiv);
  130. parentReady();
  131. inited = true;
  132. }
  133. function getAttr(attr) {
  134. if (!inited) {
  135. init();
  136. }
  137. return elementComputedStyle[attr];
  138. }
  139. var changeAttrs = [];
  140. function attrChange(attr) {
  141. if (!changeAttrs.length) {
  142. setTimeout(function () {
  143. var style = {};
  144. changeAttrs.forEach(function (attr) {
  145. style[attr] = elementComputedStyle[attr];
  146. });
  147. changeAttrs.length = 0;
  148. callbacks.forEach(function (callback) {
  149. callback(style);
  150. });
  151. }, 0);
  152. }
  153. changeAttrs.push(attr);
  154. }
  155. var callbacks = [];
  156. function onChange(callback) {
  157. if (!getSupport()) {
  158. return;
  159. }
  160. if (!inited) {
  161. init();
  162. }
  163. if (typeof callback === 'function') {
  164. callbacks.push(callback);
  165. }
  166. }
  167. function offChange(callback) {
  168. var index = callbacks.indexOf(callback);
  169. if (index >= 0) {
  170. callbacks.splice(index, 1);
  171. }
  172. }
  173. var safeAreaInsets = {
  174. get support() {
  175. return (typeof support === 'string' ? support : getSupport()).length != 0;
  176. },
  177. get top() {
  178. return getAttr('top');
  179. },
  180. get left() {
  181. return getAttr('left');
  182. },
  183. get right() {
  184. return getAttr('right');
  185. },
  186. get bottom() {
  187. return getAttr('bottom');
  188. },
  189. onChange: onChange,
  190. offChange: offChange
  191. };
  192. module.exports = safeAreaInsets;
  193. //# sourceMappingURL=index.js.map