1d9545ecff63e155d80735bfb69df75df5e43df0ac1b00f426fc74e29aa3e21d6e91a8f691b5f6e83775e14d24ed6eacd8317ba261fe19f0482d3f2db0cf09 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import Vue from 'vue';
  2. import merge from 'element-ui/src/utils/merge';
  3. import PopupManager from 'element-ui/src/utils/popup/popup-manager';
  4. import getScrollBarWidth from '../scrollbar-width';
  5. import { getStyle, addClass, removeClass, hasClass } from '../dom';
  6. let idSeed = 1;
  7. let scrollBarWidth;
  8. export default {
  9. props: {
  10. visible: {
  11. type: Boolean,
  12. default: false
  13. },
  14. openDelay: {},
  15. closeDelay: {},
  16. zIndex: {},
  17. modal: {
  18. type: Boolean,
  19. default: false
  20. },
  21. modalFade: {
  22. type: Boolean,
  23. default: true
  24. },
  25. modalClass: {},
  26. modalAppendToBody: {
  27. type: Boolean,
  28. default: false
  29. },
  30. lockScroll: {
  31. type: Boolean,
  32. default: true
  33. },
  34. closeOnPressEscape: {
  35. type: Boolean,
  36. default: false
  37. },
  38. closeOnClickModal: {
  39. type: Boolean,
  40. default: false
  41. }
  42. },
  43. beforeMount() {
  44. this._popupId = 'popup-' + idSeed++;
  45. PopupManager.register(this._popupId, this);
  46. },
  47. beforeDestroy() {
  48. PopupManager.deregister(this._popupId);
  49. PopupManager.closeModal(this._popupId);
  50. this.restoreBodyStyle();
  51. },
  52. data() {
  53. return {
  54. opened: false,
  55. bodyPaddingRight: null,
  56. computedBodyPaddingRight: 0,
  57. withoutHiddenClass: true,
  58. rendered: false
  59. };
  60. },
  61. watch: {
  62. visible(val) {
  63. if (val) {
  64. if (this._opening) return;
  65. if (!this.rendered) {
  66. this.rendered = true;
  67. Vue.nextTick(() => {
  68. this.open();
  69. });
  70. } else {
  71. this.open();
  72. }
  73. } else {
  74. this.close();
  75. }
  76. }
  77. },
  78. methods: {
  79. open(options) {
  80. if (!this.rendered) {
  81. this.rendered = true;
  82. }
  83. const props = merge({}, this.$props || this, options);
  84. if (this._closeTimer) {
  85. clearTimeout(this._closeTimer);
  86. this._closeTimer = null;
  87. }
  88. clearTimeout(this._openTimer);
  89. const openDelay = Number(props.openDelay);
  90. if (openDelay > 0) {
  91. this._openTimer = setTimeout(() => {
  92. this._openTimer = null;
  93. this.doOpen(props);
  94. }, openDelay);
  95. } else {
  96. this.doOpen(props);
  97. }
  98. },
  99. doOpen(props) {
  100. if (this.$isServer) return;
  101. if (this.willOpen && !this.willOpen()) return;
  102. if (this.opened) return;
  103. this._opening = true;
  104. const dom = this.$el;
  105. const modal = props.modal;
  106. const zIndex = props.zIndex;
  107. if (zIndex) {
  108. PopupManager.zIndex = zIndex;
  109. }
  110. if (modal) {
  111. if (this._closing) {
  112. PopupManager.closeModal(this._popupId);
  113. this._closing = false;
  114. }
  115. PopupManager.openModal(this._popupId, PopupManager.nextZIndex(), this.modalAppendToBody ? undefined : dom, props.modalClass, props.modalFade);
  116. if (props.lockScroll) {
  117. this.withoutHiddenClass = !hasClass(document.body, 'el-popup-parent--hidden');
  118. if (this.withoutHiddenClass) {
  119. this.bodyPaddingRight = document.body.style.paddingRight;
  120. this.computedBodyPaddingRight = parseInt(getStyle(document.body, 'paddingRight'), 10);
  121. }
  122. scrollBarWidth = getScrollBarWidth();
  123. let bodyHasOverflow = document.documentElement.clientHeight < document.body.scrollHeight;
  124. let bodyOverflowY = getStyle(document.body, 'overflowY');
  125. if (scrollBarWidth > 0 && (bodyHasOverflow || bodyOverflowY === 'scroll') && this.withoutHiddenClass) {
  126. document.body.style.paddingRight = this.computedBodyPaddingRight + scrollBarWidth + 'px';
  127. }
  128. addClass(document.body, 'el-popup-parent--hidden');
  129. }
  130. }
  131. if (getComputedStyle(dom).position === 'static') {
  132. dom.style.position = 'absolute';
  133. }
  134. dom.style.zIndex = PopupManager.nextZIndex();
  135. this.opened = true;
  136. this.onOpen && this.onOpen();
  137. this.doAfterOpen();
  138. },
  139. doAfterOpen() {
  140. this._opening = false;
  141. },
  142. close() {
  143. if (this.willClose && !this.willClose()) return;
  144. if (this._openTimer !== null) {
  145. clearTimeout(this._openTimer);
  146. this._openTimer = null;
  147. }
  148. clearTimeout(this._closeTimer);
  149. const closeDelay = Number(this.closeDelay);
  150. if (closeDelay > 0) {
  151. this._closeTimer = setTimeout(() => {
  152. this._closeTimer = null;
  153. this.doClose();
  154. }, closeDelay);
  155. } else {
  156. this.doClose();
  157. }
  158. },
  159. doClose() {
  160. this._closing = true;
  161. this.onClose && this.onClose();
  162. if (this.lockScroll) {
  163. setTimeout(this.restoreBodyStyle, 200);
  164. }
  165. this.opened = false;
  166. this.doAfterClose();
  167. },
  168. doAfterClose() {
  169. PopupManager.closeModal(this._popupId);
  170. this._closing = false;
  171. },
  172. restoreBodyStyle() {
  173. if (this.modal && this.withoutHiddenClass) {
  174. document.body.style.paddingRight = this.bodyPaddingRight;
  175. removeClass(document.body, 'el-popup-parent--hidden');
  176. }
  177. this.withoutHiddenClass = true;
  178. }
  179. }
  180. };
  181. export {
  182. PopupManager
  183. };