Modal.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <template>
  2. <teleport to="body">
  3. <div
  4. v-if="show"
  5. :transition="transition"
  6. >
  7. <div
  8. class="modal"
  9. @click.self="clickMask"
  10. >
  11. <div
  12. class="modal-dialog"
  13. :class="modalClass"
  14. name="dialog"
  15. >
  16. <div class="modal-content">
  17. <!--Header-->
  18. <div class="modal-header">
  19. <a
  20. v-if="showTopRightCloseButton"
  21. type="button"
  22. class="close"
  23. @click="cancel"
  24. >x</a>
  25. <h4 class="modal-title">
  26. <slot name="header">
  27. {{ title }}
  28. </slot>
  29. </h4>
  30. </div>
  31. <!--Container-->
  32. <div class="modal-body">
  33. <slot />
  34. </div>
  35. <!--Footer-->
  36. <div class="modal-footer">
  37. <button
  38. v-if="showCanelButton"
  39. type="button"
  40. class="btn btn-info"
  41. @click="cancel"
  42. >
  43. {{ cancelText }}
  44. </button>
  45. <button
  46. v-if="showOkButton"
  47. type="button"
  48. class="btn btn-primary"
  49. @click="ok"
  50. >
  51. {{ okText }}
  52. </button>
  53. <slot name="footer" />
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. <div class="modal-backdrop in" />
  59. </div>
  60. </teleport>
  61. </template>
  62. <script>
  63. import ModalFix from './ModalFix.js';
  64. export default {
  65. // eslint-disable-next-line
  66. name: 'Modal',
  67. props: {
  68. /**
  69. * 是否显示模态框
  70. */
  71. show: {
  72. type: Boolean,
  73. default: false,
  74. },
  75. title: {
  76. type: String,
  77. default: '',
  78. },
  79. small: {
  80. type: [Boolean, String],
  81. default: false,
  82. },
  83. large: {
  84. type: [Boolean, String],
  85. default: false,
  86. },
  87. full: {
  88. type: [Boolean, String],
  89. default: false,
  90. },
  91. // 为true时无法通过点击遮罩层关闭modal
  92. force: {
  93. type: Boolean,
  94. default: null,
  95. },
  96. // 自定义组件transition
  97. transition: {
  98. type: String,
  99. default: '',
  100. },
  101. // 显示确定按钮
  102. showOkButton: {
  103. type: Boolean,
  104. default: true,
  105. },
  106. // 显示取消按钮
  107. showCanelButton: {
  108. type: Boolean,
  109. default: true,
  110. },
  111. // 显示标题栏的关闭按钮
  112. showTopRightCloseButton: {
  113. type: Boolean,
  114. default: true,
  115. },
  116. },
  117. emits: ['ok', 'cancel', 'close', 'update:show'],
  118. data: function () {
  119. return {
  120. okText: this.$t('lang.modal.confirm'),
  121. cancelText: this.$t('lang.modal.cancel'),
  122. closeText: this.$t('lang.modal.close'),
  123. okClass: '',
  124. cancelClass: '',
  125. closeClass: '',
  126. };
  127. },
  128. computed: {
  129. modalClass: function () {
  130. return {
  131. 'modal-lg': this.large || this.large == 'true',
  132. 'modal-sm': this.small || this.small == 'true',
  133. 'modal-full': this.full || this.full == 'true',
  134. };
  135. },
  136. },
  137. watch: {
  138. show: function (value) {
  139. console.log('modal watch show = ' + value);
  140. // 在显示时去掉body滚动条,防止出现双滚动条
  141. if (value) {
  142. if (document.body.className.indexOf('modal-open') < 0) {
  143. document.body.className += ' modal-open';
  144. }
  145. } else {
  146. this.$nextTick(function () {
  147. ModalFix.fix();
  148. });
  149. }
  150. },
  151. },
  152. created: function () {
  153. if (this.show) {
  154. if (document.body.className.indexOf('modal-open') < 0) {
  155. document.body.className += ' modal-open';
  156. }
  157. }
  158. },
  159. methods: {
  160. ok: function () {
  161. this.$emit('ok');
  162. this.$emit('update:show', false);
  163. this.$nextTick(function () {
  164. ModalFix.fix();
  165. });
  166. },
  167. cancel: function () {
  168. this.$emit('cancel');
  169. this.$emit('update:show', false);
  170. this.$nextTick(function () {
  171. ModalFix.fix();
  172. });
  173. },
  174. close: function () {
  175. this.$emit('close');
  176. this.$emit('update:show', false);
  177. this.$nextTick(function () {
  178. ModalFix.fix();
  179. });
  180. },
  181. // 点击遮罩层
  182. clickMask: function () {
  183. if (!this.force) {
  184. this.cancel();
  185. this.$nextTick(function () {
  186. ModalFix.fix();
  187. });
  188. }
  189. },
  190. },
  191. };
  192. </script>
  193. <style scoped>
  194. .modal {
  195. display: block;
  196. }
  197. .modal-transition {
  198. transition: all 0.6s ease;
  199. }
  200. .modal-leave {
  201. /* 样式没什么用,但可以让根标签的transitionEnd生效,以去掉modal-leave */
  202. border-radius: 1px !important;
  203. }
  204. .modal-transition .modal-dialog,
  205. .modal-transition .modal-backdrop {
  206. transition: all 0.5s ease;
  207. }
  208. .modal-enter .modal-dialog,
  209. .modal-leave .modal-dialog {
  210. opacity: 0;
  211. transform: translateY(-30%);
  212. }
  213. .modal-enter .modal-backdrop,
  214. .modal-leave .modal-backdrop {
  215. opacity: 0;
  216. }
  217. .modal-full {
  218. width: 95%;
  219. }
  220. .modal-lg {
  221. width: 75%;
  222. }
  223. .modal-sm {
  224. width: 50%;
  225. }
  226. </style>