index.vue 3.1 KB

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