项目原始demo,不改动
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 

196 rivejä
5.3 KiB

  1. // Components
  2. import VOverlay from '../../components/VOverlay'; // Utilities
  3. import { keyCodes, addOnceEventListener, addPassiveEventListener, getZIndex } from '../../util/helpers'; // Types
  4. import Vue from 'vue';
  5. /* @vue/component */
  6. export default Vue.extend().extend({
  7. name: 'overlayable',
  8. props: {
  9. hideOverlay: Boolean,
  10. overlayColor: String,
  11. overlayOpacity: [Number, String]
  12. },
  13. data() {
  14. return {
  15. overlay: null
  16. };
  17. },
  18. watch: {
  19. hideOverlay(value) {
  20. if (!this.isActive) return;
  21. if (value) this.removeOverlay();else this.genOverlay();
  22. }
  23. },
  24. beforeDestroy() {
  25. this.removeOverlay();
  26. },
  27. methods: {
  28. createOverlay() {
  29. const overlay = new VOverlay({
  30. propsData: {
  31. absolute: this.absolute,
  32. value: false,
  33. color: this.overlayColor,
  34. opacity: this.overlayOpacity
  35. }
  36. });
  37. overlay.$mount();
  38. const parent = this.absolute ? this.$el.parentNode : document.querySelector('[data-app]');
  39. parent && parent.insertBefore(overlay.$el, parent.firstChild);
  40. this.overlay = overlay;
  41. },
  42. genOverlay() {
  43. this.hideScroll();
  44. if (this.hideOverlay) return;
  45. if (!this.overlay) this.createOverlay();
  46. requestAnimationFrame(() => {
  47. if (!this.overlay) return;
  48. if (this.activeZIndex !== undefined) {
  49. this.overlay.zIndex = String(this.activeZIndex - 1);
  50. } else if (this.$el) {
  51. this.overlay.zIndex = getZIndex(this.$el);
  52. }
  53. });
  54. if (this.overlay) {
  55. this.overlay.value = true;
  56. }
  57. return true;
  58. },
  59. /** removeOverlay(false) will not restore the scollbar afterwards */
  60. removeOverlay(showScroll = true) {
  61. if (this.overlay) {
  62. addOnceEventListener(this.overlay.$el, 'transitionend', () => {
  63. if (!this.overlay || !this.overlay.$el || !this.overlay.$el.parentNode || this.overlay.value) return;
  64. this.overlay.$el.parentNode.removeChild(this.overlay.$el);
  65. this.overlay.$destroy();
  66. this.overlay = null;
  67. });
  68. this.overlay.value = false;
  69. }
  70. showScroll && this.showScroll();
  71. },
  72. scrollListener(e) {
  73. if (e.type === 'keydown') {
  74. if (['INPUT', 'TEXTAREA', 'SELECT'].includes(e.target.tagName) || // https://github.com/vuetifyjs/vuetify/issues/4715
  75. e.target.isContentEditable) return;
  76. const up = [keyCodes.up, keyCodes.pageup];
  77. const down = [keyCodes.down, keyCodes.pagedown];
  78. if (up.includes(e.keyCode)) {
  79. e.deltaY = -1;
  80. } else if (down.includes(e.keyCode)) {
  81. e.deltaY = 1;
  82. } else {
  83. return;
  84. }
  85. }
  86. if (e.target === this.overlay || e.type !== 'keydown' && e.target === document.body || this.checkPath(e)) e.preventDefault();
  87. },
  88. hasScrollbar(el) {
  89. if (!el || el.nodeType !== Node.ELEMENT_NODE) return false;
  90. const style = window.getComputedStyle(el);
  91. return ['auto', 'scroll'].includes(style.overflowY) && el.scrollHeight > el.clientHeight;
  92. },
  93. shouldScroll(el, delta) {
  94. if (el.scrollTop === 0 && delta < 0) return true;
  95. return el.scrollTop + el.clientHeight === el.scrollHeight && delta > 0;
  96. },
  97. isInside(el, parent) {
  98. if (el === parent) {
  99. return true;
  100. } else if (el === null || el === document.body) {
  101. return false;
  102. } else {
  103. return this.isInside(el.parentNode, parent);
  104. }
  105. },
  106. checkPath(e) {
  107. const path = e.path || this.composedPath(e);
  108. const delta = e.deltaY;
  109. if (e.type === 'keydown' && path[0] === document.body) {
  110. const dialog = this.$refs.dialog; // getSelection returns null in firefox in some edge cases, can be ignored
  111. const selected = window.getSelection().anchorNode;
  112. if (dialog && this.hasScrollbar(dialog) && this.isInside(selected, dialog)) {
  113. return this.shouldScroll(dialog, delta);
  114. }
  115. return true;
  116. }
  117. for (let index = 0; index < path.length; index++) {
  118. const el = path[index];
  119. if (el === document) return true;
  120. if (el === document.documentElement) return true;
  121. if (el === this.$refs.content) return true;
  122. if (this.hasScrollbar(el)) return this.shouldScroll(el, delta);
  123. }
  124. return true;
  125. },
  126. /**
  127. * Polyfill for Event.prototype.composedPath
  128. */
  129. composedPath(e) {
  130. if (e.composedPath) return e.composedPath();
  131. const path = [];
  132. let el = e.target;
  133. while (el) {
  134. path.push(el);
  135. if (el.tagName === 'HTML') {
  136. path.push(document);
  137. path.push(window);
  138. return path;
  139. }
  140. el = el.parentElement;
  141. }
  142. return path;
  143. },
  144. hideScroll() {
  145. if (this.$vuetify.breakpoint.smAndDown) {
  146. document.documentElement.classList.add('overflow-y-hidden');
  147. } else {
  148. addPassiveEventListener(window, 'wheel', this.scrollListener, {
  149. passive: false
  150. });
  151. window.addEventListener('keydown', this.scrollListener);
  152. }
  153. },
  154. showScroll() {
  155. document.documentElement.classList.remove('overflow-y-hidden');
  156. window.removeEventListener('wheel', this.scrollListener);
  157. window.removeEventListener('keydown', this.scrollListener);
  158. }
  159. }
  160. });
  161. //# sourceMappingURL=index.js.map