ScrollPopup.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <template>
  2. <BasicModal type="bottom" v-model:open="getOpen">
  3. <view class="popup-content flex flex-y" :style="getStyle">
  4. <view class="popup-content__close" @click="getOpen = false" v-if="close">
  5. <text>关闭按钮</text>
  6. <image :src="getFileUrl('/modal/close.png')" mode="aspectFill"></image>
  7. </view>
  8. <view class="popup-content__header" v-if="title || $slots.title">
  9. <slot name="title">
  10. <view class="default-header-slot">{{ title }}</view>
  11. </slot>
  12. <slot name="search"></slot>
  13. </view>
  14. <scroll-view
  15. @scrolltolower="emit('scrolltolower')"
  16. scroll-y
  17. class="popup-content__scroll flex-1"
  18. :style="[scrollViewStyle]"
  19. >
  20. <view style="overflow: hidden;">
  21. <slot> 中间区域 可以滚动的哦~ </slot>
  22. </view>
  23. </scroll-view>
  24. <view class="popup-content__footer" v-if="!hideFooter">
  25. <slot name="footer" >
  26. <view class="default-footer-slot">
  27. <view v-if="showCancelBtn" class="default-footer-slot___cancel" @click="getOpen = false">取消</view>
  28. <view class="default-footer-slot___ok" @click="emit('ok')">确认</view>
  29. </view>
  30. </slot>
  31. </view>
  32. </view>
  33. </BasicModal>
  34. </template>
  35. <script setup>
  36. import { computed } from "vue";
  37. import BasicModal from "./BasicModal.vue"
  38. import { getFileUrl } from "@/utils/file.js";
  39. const emit = defineEmits(['scrolltolower', 'update:open', 'ok'])
  40. const props = defineProps({
  41. open: { type: Boolean },
  42. height: { type: [Number, String] },
  43. title: { type: String },
  44. styles: { type: Object, default: () => {} },
  45. scrollViewStyle: { type: Object, default: () => {} },
  46. close: { type: Boolean, default: true },
  47. hideFooter: { type: Boolean, default: false },
  48. showCancelBtn: { type: Boolean, default: false }
  49. })
  50. const getOpen = computed({
  51. get: () => props.open,
  52. set: (v) => emit('update:open', v)
  53. })
  54. const getStyle = computed(() => {
  55. const { height } = props;
  56. let s = `${height}`;
  57. s = height ? `${s.replace('rpx', '')}rpx` : 'calc(100vh - 330rpx)';
  58. return {
  59. height: s,
  60. ...props.styles
  61. }
  62. })
  63. </script>
  64. <style scoped lang="scss">
  65. .popup-content {
  66. height: 100%;
  67. border-radius: 16rpx 16rpx 0 0;
  68. background: #fff;
  69. overflow: hidden;
  70. padding-top: 36rpx;
  71. position: relative;
  72. &__close{
  73. position: absolute;
  74. right: 0;
  75. top: 0;
  76. z-index: 3;
  77. padding: 34rpx;
  78. image{
  79. width: 22rpx;
  80. height: 24rpx;
  81. }
  82. }
  83. &__header {
  84. position: sticky;
  85. top: 0;
  86. z-index: 2;
  87. .default-header-slot{
  88. font-weight: bold;
  89. font-size: 36rpx;
  90. color: #010101;
  91. line-height: 35rpx;
  92. text-align: center;
  93. padding-bottom: 36rpx;
  94. }
  95. }
  96. &__scroll {
  97. // padding: 12rpx 30rpx 0;
  98. padding: 12rpx 30rpx 0;
  99. height: 0;
  100. box-sizing: border-box;
  101. overflow: hidden;
  102. }
  103. &__footer {
  104. position: sticky;
  105. bottom: 0;
  106. padding: 20rpx 30rpx;
  107. border-top: 1rpx solid #EEEEEE;
  108. .default-footer-slot{
  109. display: flex;
  110. margin: 0 -15rpx;
  111. &___cancel, &___ok{
  112. width: 100%;
  113. border-radius: 8rpx;
  114. font-weight: bold;
  115. font-size: 28rpx;
  116. line-height: 80rpx;
  117. text-align: center;
  118. letter-spacing: 2rpx;
  119. margin: 0 15rpx;
  120. border: 0.2rpx solid #1677FF;
  121. color: #1677FF;
  122. }
  123. &___ok{
  124. color: #FFFFFF;
  125. background: #1677FF;
  126. }
  127. }
  128. }
  129. }
  130. </style>