index.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import { context } from './context';
  2. import { TouchMixin } from '../touch';
  3. import { on, off, preventDefault } from '../../utils/event';
  4. import { openOverlay, closeOverlay, updateOverlay } from './overlay';
  5. import { getScrollEventTarget } from '../../utils/scroll';
  6. export var PopupMixin = {
  7. mixins: [TouchMixin],
  8. props: {
  9. // whether to show popup
  10. value: Boolean,
  11. // whether to show overlay
  12. overlay: Boolean,
  13. // overlay custom style
  14. overlayStyle: Object,
  15. // overlay custom class name
  16. overlayClass: String,
  17. // whether to close popup when click overlay
  18. closeOnClickOverlay: Boolean,
  19. // z-index
  20. zIndex: [String, Number],
  21. // return the mount node for popup
  22. getContainer: [String, Function],
  23. // prevent body scroll
  24. lockScroll: {
  25. type: Boolean,
  26. "default": true
  27. },
  28. // whether to lazy render
  29. lazyRender: {
  30. type: Boolean,
  31. "default": true
  32. }
  33. },
  34. data: function data() {
  35. return {
  36. inited: this.value
  37. };
  38. },
  39. computed: {
  40. shouldRender: function shouldRender() {
  41. return this.inited || !this.lazyRender;
  42. }
  43. },
  44. watch: {
  45. value: function value(val) {
  46. var type = val ? 'open' : 'close';
  47. this.inited = this.inited || this.value;
  48. this[type]();
  49. this.$emit(type);
  50. },
  51. getContainer: function getContainer() {
  52. this.move();
  53. },
  54. overlay: function overlay() {
  55. this.renderOverlay();
  56. }
  57. },
  58. mounted: function mounted() {
  59. if (this.getContainer) {
  60. this.move();
  61. }
  62. if (this.value) {
  63. this.open();
  64. }
  65. },
  66. activated: function activated() {
  67. /* istanbul ignore next */
  68. if (this.value) {
  69. this.open();
  70. }
  71. },
  72. beforeDestroy: function beforeDestroy() {
  73. this.close();
  74. if (this.getContainer && this.$parent && this.$parent.$el) {
  75. this.$parent.$el.appendChild(this.$el);
  76. }
  77. },
  78. deactivated: function deactivated() {
  79. /* istanbul ignore next */
  80. this.close();
  81. },
  82. methods: {
  83. open: function open() {
  84. /* istanbul ignore next */
  85. if (this.$isServer || this.opened) {
  86. return;
  87. } // cover default zIndex
  88. if (this.zIndex !== undefined) {
  89. context.zIndex = this.zIndex;
  90. }
  91. this.opened = true;
  92. this.renderOverlay();
  93. if (this.lockScroll) {
  94. on(document, 'touchstart', this.touchStart);
  95. on(document, 'touchmove', this.onTouchMove);
  96. if (!context.lockCount) {
  97. document.body.classList.add('van-overflow-hidden');
  98. }
  99. context.lockCount++;
  100. }
  101. },
  102. close: function close() {
  103. if (!this.opened) {
  104. return;
  105. }
  106. if (this.lockScroll) {
  107. context.lockCount--;
  108. off(document, 'touchstart', this.touchStart);
  109. off(document, 'touchmove', this.onTouchMove);
  110. if (!context.lockCount) {
  111. document.body.classList.remove('van-overflow-hidden');
  112. }
  113. }
  114. this.opened = false;
  115. closeOverlay(this);
  116. this.$emit('input', false);
  117. },
  118. move: function move() {
  119. var container;
  120. var getContainer = this.getContainer;
  121. if (getContainer) {
  122. container = typeof getContainer === 'string' ? document.querySelector(getContainer) : getContainer();
  123. } else if (this.$parent) {
  124. container = this.$parent.$el;
  125. }
  126. if (container && container !== this.$el.parentNode) {
  127. container.appendChild(this.$el);
  128. }
  129. if (this.overlay) {
  130. updateOverlay();
  131. }
  132. },
  133. onTouchMove: function onTouchMove(event) {
  134. this.touchMove(event);
  135. var direction = this.deltaY > 0 ? '10' : '01';
  136. var el = getScrollEventTarget(event.target, this.$el);
  137. var scrollHeight = el.scrollHeight,
  138. offsetHeight = el.offsetHeight,
  139. scrollTop = el.scrollTop;
  140. var status = '11';
  141. /* istanbul ignore next */
  142. if (scrollTop === 0) {
  143. status = offsetHeight >= scrollHeight ? '00' : '01';
  144. } else if (scrollTop + offsetHeight >= scrollHeight) {
  145. status = '10';
  146. }
  147. /* istanbul ignore next */
  148. if (status !== '11' && this.direction === 'vertical' && !(parseInt(status, 2) & parseInt(direction, 2))) {
  149. preventDefault(event, true);
  150. }
  151. },
  152. renderOverlay: function renderOverlay() {
  153. if (this.$isServer || !this.value) {
  154. return;
  155. }
  156. if (this.overlay) {
  157. openOverlay(this, {
  158. zIndex: context.zIndex++,
  159. className: this.overlayClass,
  160. customStyle: this.overlayStyle
  161. });
  162. } else {
  163. closeOverlay(this);
  164. }
  165. this.updateZIndex();
  166. },
  167. updateZIndex: function updateZIndex() {
  168. var _this = this;
  169. this.$nextTick(function () {
  170. _this.$el.style.zIndex = context.zIndex++;
  171. });
  172. }
  173. }
  174. };