index.js 5.2 KB

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