index.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <template>
  2. <Overlay
  3. ref="overlayDomInstanceRef"
  4. :visible="props.visible"
  5. :useMask="props.useMask"
  6. :maskColor="props.overlayColor"
  7. :isFullScreen="props.isFullScreen"
  8. @onOverlayClick="onOverlayClick"
  9. >
  10. <div
  11. v-if="isDrawerShow"
  12. ref="drawerDomRef"
  13. :class="{
  14. 'drawer': true,
  15. 'origin-bottom': props.popDirection === 'bottom',
  16. 'origin-right': props.popDirection === 'right',
  17. 'slide-bottom': visible && props.popDirection === 'bottom',
  18. 'slide-right': visible && props.popDirection === 'right',
  19. }"
  20. :style="{
  21. minHeight: styles.minHeight,
  22. maxHeight: styles.maxHeight,
  23. borderRadius: styles.borderRadius,
  24. boxShadow: styles.boxShadow,
  25. width: styles.width,
  26. }"
  27. >
  28. <div class="drawer-container">
  29. <slot />
  30. </div>
  31. </div>
  32. </Overlay>
  33. </template>
  34. <script setup lang="ts">
  35. import { ref, watch } from '../../../adapter-vue';
  36. import Overlay from '../../common/Overlay/index.vue';
  37. interface IProps {
  38. visible: boolean;
  39. popDirection: 'top' | 'right' | 'bottom' | 'left';
  40. useMask?: boolean;
  41. isFullScreen?: boolean | undefined;
  42. overlayColor?: string | undefined;
  43. drawerStyle?: {
  44. bottom?: Record<string, any> | undefined;
  45. right?: Record<string, any> | undefined;
  46. left?: Record<string, any> | undefined;
  47. top?: Record<string, any> | undefined;
  48. };
  49. }
  50. interface IEmits {
  51. (e: 'onOverlayClick', event: Event): void;
  52. }
  53. const emits = defineEmits<IEmits>();
  54. const props = withDefaults(defineProps<IProps>(), {
  55. visible: true,
  56. useMask: true,
  57. isFullScreen: true,
  58. popDirection: 'bottom',
  59. drawerStyle: () => ({}),
  60. });
  61. const drawerDomRef = ref<HTMLElement>();
  62. const overlayDomInstanceRef = ref<InstanceType<typeof Overlay>>();
  63. const isDrawerShow = ref<boolean>(false);
  64. const styles = ref(props.drawerStyle[props.popDirection] || {});
  65. watch(() => props.visible, (visible: boolean) => {
  66. if (visible) {
  67. isDrawerShow.value = true;
  68. } else {
  69. setTimeout(() => {
  70. isDrawerShow.value = false;
  71. }, 150);
  72. }
  73. }, {
  74. immediate: true,
  75. });
  76. function onOverlayClick(e: Event) {
  77. emits('onOverlayClick', e);
  78. }
  79. defineExpose({
  80. drawerDomRef,
  81. overlayDomRef: overlayDomInstanceRef.value?.overlayDomRef,
  82. });
  83. </script>
  84. <style scoped lang="scss">
  85. :not(not) {
  86. display: flex;
  87. flex-direction: column;
  88. box-sizing: border-box;
  89. min-width: 0;
  90. }
  91. .drawer {
  92. position: absolute;
  93. z-index: 1;
  94. background-color: #fff;
  95. overflow: hidden;
  96. transition: transform 0.15s ease-out;
  97. .drawer-container {
  98. background-color: #fff;
  99. height: 100%;
  100. width: 100%;
  101. }
  102. }
  103. .origin-bottom {
  104. bottom: 0;
  105. left: 0;
  106. right: 0;
  107. transform: translateY(100%);
  108. animation: slide-from-bottom 0.15s ease-out;
  109. }
  110. .origin-right {
  111. top: 0;
  112. bottom: 0;
  113. right: 0;
  114. transform: translateX(100%);
  115. animation: slide-from-right 0.15s ease-out;
  116. }
  117. .slide-bottom {
  118. transform: translateY(0);
  119. }
  120. .slide-right {
  121. transform: translateX(0);
  122. }
  123. @keyframes slide-from-bottom {
  124. 0% {
  125. transform: translateY(100%);
  126. }
  127. 100% {
  128. transform: translateY(0);
  129. }
  130. }
  131. @keyframes slide-from-right {
  132. 0% {
  133. transform: translateX(100%);
  134. }
  135. 100% {
  136. transform: translateX(0);
  137. }
  138. }
  139. </style>