dialog.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <template>
  2. <transition name="modal">
  3. <div v-if="show" class="modal" :style="modalStyle">
  4. <div class="modal-overlay" @click="close"></div>
  5. <div class="modal-content" :style="modalcontentStyle">
  6. <div class="modal-header">
  7. <div>
  8. <slot name="title">
  9. <span class="titleSpan">{{ title }}</span>
  10. </slot>
  11. </div>
  12. <div>
  13. <i class="el-icon-close" @click="close"></i>
  14. </div>
  15. </div>
  16. <div class="modal-body">
  17. <slot name="content"></slot>
  18. </div>
  19. <div class="modal-footer" :class="{ 'sticky-footer': stickyFooter }">
  20. <slot name="footer"></slot>
  21. </div>
  22. </div>
  23. </div>
  24. </transition>
  25. </template>
  26. <script>
  27. export default {
  28. props: {
  29. show: {
  30. type: Boolean,
  31. required: true
  32. },
  33. restrictTo: {
  34. type: String,
  35. default: ''
  36. },
  37. title: {
  38. type: String,
  39. default: '弹层标题'
  40. },
  41. width: {
  42. type: [String, Number],
  43. default: 'auto'
  44. },
  45. height: {
  46. type: [String, Number],
  47. default: 'auto'
  48. },
  49. stickyFooter: {
  50. type: Boolean,
  51. default: true
  52. }
  53. },
  54. computed: {
  55. modalStyle() {
  56. if (this.restrictTo) {
  57. const el = document.querySelector(this.restrictTo);
  58. if (el) {
  59. return {
  60. position: 'absolute',
  61. top: `${el.offsetTop}px`,
  62. left: `${el.offsetLeft}px`,
  63. width: `${el.offsetWidth}px`,
  64. height: `${el.offsetHeight}px`,
  65. display: 'flex',
  66. alignItems: 'center',
  67. justifyContent: 'center',
  68. };
  69. }
  70. }
  71. return {
  72. display: 'flex',
  73. alignItems: 'center',
  74. justifyContent: 'center'
  75. };
  76. },
  77. modalcontentStyle(){
  78. const style = {};
  79. if (this.width !== 'auto') {
  80. style.width = this.width + 'px';
  81. }
  82. if (this.height !== 'auto') {
  83. style.height = this.height + 'px';
  84. }
  85. return style;
  86. }
  87. },
  88. methods: {
  89. close() {
  90. this.$emit('close');
  91. }
  92. },
  93. mounted() {
  94. document.body.style.overflow = 'hidden';
  95. },
  96. }
  97. </script>
  98. <style scoped>
  99. .modal {
  100. z-index: 99;
  101. font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
  102. }
  103. .modal-overlay {
  104. position: absolute;
  105. top: 0;
  106. left: 0;
  107. width: 100%;
  108. height: 100%;
  109. background-color: rgba(0, 0, 0, 0.5);
  110. }
  111. .modal-content {
  112. background-color: #fff;
  113. padding: 20px;
  114. z-index: 999;
  115. BORDER-RADIUS: 10px;
  116. position: relative;
  117. }
  118. .modal-body {
  119. margin-bottom: 20px;
  120. font-size: 15px;
  121. }
  122. .modal-footer {
  123. display: flex;
  124. justify-content: flex-end;
  125. }
  126. .modal-header{
  127. display: flex;
  128. justify-content: space-between;
  129. padding-bottom: 20px;
  130. }
  131. .sticky-footer {
  132. position: absolute;
  133. bottom: 20px;
  134. right: 30px;
  135. }
  136. .titleSpan{
  137. font-size: 18px;
  138. color: #303133;
  139. }
  140. /* 过渡效果 */
  141. .modal-enter-active,
  142. .modal-leave-active {
  143. transition: opacity 0.25s;
  144. }
  145. .modal-enter,
  146. .modal-leave-to {
  147. opacity: 0;
  148. }
  149. </style>