index.vue 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. <template>
  2. <view
  3. v-if="show"
  4. class="zy-half-screen-dialog"
  5. :class="extClass"
  6. data-target="screen-dialog"
  7. @click="tapMask"
  8. >
  9. <view
  10. class="zy-half-screen-dialog-content"
  11. :style="{ height: height }"
  12. :data-visible="visible"
  13. :animation="contentAnimation"
  14. @transitionend="updateVisible"
  15. @click.stop=""
  16. >
  17. <slot></slot>
  18. </view>
  19. </view>
  20. </template>
  21. <script lang="ts" setup>
  22. import { nextTick, ref, watch } from 'vue';
  23. const props = defineProps({
  24. show: {
  25. type: Boolean,
  26. default: false,
  27. },
  28. height: {
  29. type: String,
  30. default: '80%',
  31. },
  32. extClass: {
  33. type: String,
  34. default: '',
  35. },
  36. });
  37. const maskClosable = ref(true);
  38. const duration = 300;
  39. const contentAnimation = ref(null);
  40. const visible = ref(false);
  41. const emits = defineEmits(['update:show']);
  42. const tapMask = (e) => {
  43. if (e.currentTarget.dataset.target !== 'screen-dialog') {
  44. return;
  45. }
  46. if (maskClosable.value) {
  47. close();
  48. }
  49. };
  50. const updateVisible = (e) => {
  51. const { visible } = e.currentTarget.dataset;
  52. nextTick(() => {
  53. if (!visible) {
  54. emits('update:show', visible);
  55. }
  56. });
  57. };
  58. const open = () => {
  59. const up = uni.createAnimation({
  60. duration,
  61. });
  62. up.translateY(0).step();
  63. contentAnimation.value = up.export();
  64. visible.value = true;
  65. };
  66. const close = () => {
  67. const down = uni.createAnimation({
  68. duration,
  69. });
  70. down.translateY('120%').step();
  71. contentAnimation.value = down.export();
  72. visible.value = false;
  73. };
  74. watch(
  75. () => props.show,
  76. (v) => {
  77. visible.value = v;
  78. if (v) {
  79. nextTick(() => open());
  80. } else {
  81. nextTick(() => close());
  82. }
  83. }
  84. );
  85. </script>
  86. <style lang="scss" scoped>
  87. .zy-half-screen-dialog {
  88. height: 100%;
  89. width: 100%;
  90. background-color: #00000083;
  91. position: fixed;
  92. top: 0;
  93. left: 0;
  94. z-index: 999999;
  95. }
  96. .zy-half-screen-dialog-content {
  97. position: absolute;
  98. bottom: 0;
  99. left: 0;
  100. width: 100%;
  101. background-color: #ffffff;
  102. border-top-left-radius: 30rpx;
  103. border-top-right-radius: 30rpx;
  104. overflow: hidden;
  105. min-height: 20%;
  106. height: 80%;
  107. transform: translateY('100%');
  108. }
  109. </style>