PortalWrapper.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = void 0;
  7. exports.getOpenCount = getOpenCount;
  8. var _vue = require("vue");
  9. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  10. var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
  11. var _vueTypes = _interopRequireDefault(require("./vue-types"));
  12. var _switchScrollingEffect = _interopRequireDefault(require("./switchScrollingEffect"));
  13. var _setStyle = _interopRequireDefault(require("./setStyle"));
  14. var _Portal = _interopRequireDefault(require("./Portal"));
  15. var _canUseDom = _interopRequireDefault(require("./canUseDom"));
  16. var _scrollLocker = _interopRequireDefault(require("../vc-util/Dom/scrollLocker"));
  17. var _raf = _interopRequireDefault(require("./raf"));
  18. var openCount = 0;
  19. var supportDom = (0, _canUseDom.default)();
  20. /** @private Test usage only */
  21. function getOpenCount() {
  22. return process.env.NODE_ENV === 'test' ? openCount : 0;
  23. }
  24. // https://github.com/ant-design/ant-design/issues/19340
  25. // https://github.com/ant-design/ant-design/issues/19332
  26. var cacheOverflow = {};
  27. var getParent = function getParent(getContainer) {
  28. if (!supportDom) {
  29. return null;
  30. }
  31. if (getContainer) {
  32. if (typeof getContainer === 'string') {
  33. return document.querySelectorAll(getContainer)[0];
  34. }
  35. if (typeof getContainer === 'function') {
  36. return getContainer();
  37. }
  38. if ((0, _typeof2.default)(getContainer) === 'object' && getContainer instanceof window.HTMLElement) {
  39. return getContainer;
  40. }
  41. }
  42. return document.body;
  43. };
  44. var _default2 = (0, _vue.defineComponent)({
  45. compatConfig: {
  46. MODE: 3
  47. },
  48. name: 'PortalWrapper',
  49. inheritAttrs: false,
  50. props: {
  51. wrapperClassName: String,
  52. forceRender: {
  53. type: Boolean,
  54. default: undefined
  55. },
  56. getContainer: _vueTypes.default.any,
  57. visible: {
  58. type: Boolean,
  59. default: undefined
  60. }
  61. },
  62. setup: function setup(props, _ref) {
  63. var slots = _ref.slots;
  64. var container = (0, _vue.ref)();
  65. var componentRef = (0, _vue.ref)();
  66. var rafId = (0, _vue.ref)();
  67. var scrollLocker = new _scrollLocker.default({
  68. container: getParent(props.getContainer)
  69. });
  70. var removeCurrentContainer = function removeCurrentContainer() {
  71. var _container$value, _container$value$pare;
  72. // Portal will remove from `parentNode`.
  73. // Let's handle this again to avoid refactor issue.
  74. (_container$value = container.value) === null || _container$value === void 0 ? void 0 : (_container$value$pare = _container$value.parentNode) === null || _container$value$pare === void 0 ? void 0 : _container$value$pare.removeChild(container.value);
  75. };
  76. var attachToParent = function attachToParent() {
  77. var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
  78. if (force || container.value && !container.value.parentNode) {
  79. var parent = getParent(props.getContainer);
  80. if (parent) {
  81. parent.appendChild(container.value);
  82. return true;
  83. }
  84. return false;
  85. }
  86. return true;
  87. };
  88. // attachToParent();
  89. var getContainer = function getContainer() {
  90. if (!supportDom) {
  91. return null;
  92. }
  93. if (!container.value) {
  94. container.value = document.createElement('div');
  95. attachToParent(true);
  96. }
  97. setWrapperClassName();
  98. return container.value;
  99. };
  100. var setWrapperClassName = function setWrapperClassName() {
  101. var wrapperClassName = props.wrapperClassName;
  102. if (container.value && wrapperClassName && wrapperClassName !== container.value.className) {
  103. container.value.className = wrapperClassName;
  104. }
  105. };
  106. (0, _vue.onUpdated)(function () {
  107. setWrapperClassName();
  108. attachToParent();
  109. });
  110. /**
  111. * Enhance ./switchScrollingEffect
  112. * 1. Simulate document body scroll bar with
  113. * 2. Record body has overflow style and recover when all of PortalWrapper invisible
  114. * 3. Disable body scroll when PortalWrapper has open
  115. *
  116. * @memberof PortalWrapper
  117. */
  118. var switchScrolling = function switchScrolling() {
  119. if (openCount === 1 && !Object.keys(cacheOverflow).length) {
  120. (0, _switchScrollingEffect.default)();
  121. // Must be set after switchScrollingEffect
  122. cacheOverflow = (0, _setStyle.default)({
  123. overflow: 'hidden',
  124. overflowX: 'hidden',
  125. overflowY: 'hidden'
  126. });
  127. } else if (!openCount) {
  128. (0, _setStyle.default)(cacheOverflow);
  129. cacheOverflow = {};
  130. (0, _switchScrollingEffect.default)(true);
  131. }
  132. };
  133. var instance = (0, _vue.getCurrentInstance)();
  134. (0, _vue.onMounted)(function () {
  135. var init = false;
  136. (0, _vue.watch)([function () {
  137. return props.visible;
  138. }, function () {
  139. return props.getContainer;
  140. }], function (_ref2, _ref3) {
  141. var _ref4 = (0, _slicedToArray2.default)(_ref2, 2),
  142. visible = _ref4[0],
  143. getContainer = _ref4[1];
  144. var _ref5 = (0, _slicedToArray2.default)(_ref3, 2),
  145. prevVisible = _ref5[0],
  146. prevGetContainer = _ref5[1];
  147. // Update count
  148. if (supportDom && getParent(props.getContainer) === document.body) {
  149. if (visible && !prevVisible) {
  150. openCount += 1;
  151. } else if (init) {
  152. openCount -= 1;
  153. }
  154. }
  155. if (init) {
  156. // Clean up container if needed
  157. var getContainerIsFunc = typeof getContainer === 'function' && typeof prevGetContainer === 'function';
  158. if (getContainerIsFunc ? getContainer.toString() !== prevGetContainer.toString() : getContainer !== prevGetContainer) {
  159. removeCurrentContainer();
  160. }
  161. // updateScrollLocker
  162. if (visible && visible !== prevVisible && supportDom && getParent(getContainer) !== scrollLocker.getContainer()) {
  163. scrollLocker.reLock({
  164. container: getParent(getContainer)
  165. });
  166. }
  167. }
  168. init = true;
  169. }, {
  170. immediate: true,
  171. flush: 'post'
  172. });
  173. (0, _vue.nextTick)(function () {
  174. if (!attachToParent()) {
  175. rafId.value = (0, _raf.default)(function () {
  176. instance.update();
  177. });
  178. }
  179. });
  180. });
  181. (0, _vue.onBeforeUnmount)(function () {
  182. var visible = props.visible,
  183. getContainer = props.getContainer;
  184. if (supportDom && getParent(getContainer) === document.body) {
  185. // 离开时不会 render, 导到离开时数值不变,改用 func 。。
  186. openCount = visible && openCount ? openCount - 1 : openCount;
  187. }
  188. removeCurrentContainer();
  189. _raf.default.cancel(rafId.value);
  190. });
  191. return function () {
  192. var forceRender = props.forceRender,
  193. visible = props.visible;
  194. var portal = null;
  195. var childProps = {
  196. getOpenCount: function getOpenCount() {
  197. return openCount;
  198. },
  199. getContainer: getContainer,
  200. switchScrollingEffect: switchScrolling,
  201. scrollLocker: scrollLocker
  202. };
  203. if (forceRender || visible || componentRef.value) {
  204. portal = (0, _vue.createVNode)(_Portal.default, {
  205. "getContainer": getContainer,
  206. "ref": componentRef
  207. }, {
  208. default: function _default() {
  209. var _slots$default;
  210. return (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots, childProps);
  211. }
  212. });
  213. }
  214. return portal;
  215. };
  216. }
  217. });
  218. exports.default = _default2;