2a91defe91ebb681d4d2d6ce7088f2462a44e49e.svn-base 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <template>
  2. <a-modal
  3. ref="modal"
  4. :class="getClass(modalClass)"
  5. :style="getStyle(modalStyle)"
  6. :visible="visible"
  7. v-bind="_attrs"
  8. v-on="$listeners"
  9. @ok="handleOk"
  10. @cancel="handleCancel"
  11. destroyOnClose
  12. >
  13. <slot></slot>
  14. <!--有设置标题-->
  15. <template v-if="!isNoTitle" slot="title">
  16. <a-row class="j-modal-title-row" type="flex">
  17. <a-col class="left">
  18. <slot name="title">{{ title }}</slot>
  19. </a-col>
  20. <a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
  21. <a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
  22. </a-col>
  23. </a-row>
  24. </template>
  25. <!--没有设置标题-->
  26. <template v-else slot="title">
  27. <a-row class="j-modal-title-row" type="flex">
  28. <a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
  29. <a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
  30. </a-col>
  31. </a-row>
  32. </template>
  33. <!-- 处理 scopedSlots -->
  34. <template v-for="slotName of scopedSlotsKeys" :slot="slotName">
  35. <slot :name="slotName"></slot>
  36. </template>
  37. <!-- 处理 slots -->
  38. <template v-for="slotName of slotsKeys" v-slot:[slotName]>
  39. <slot :name="slotName"></slot>
  40. </template>
  41. </a-modal>
  42. </template>
  43. <script>
  44. import { getClass, getStyle } from '@/utils/props-util'
  45. import { triggerWindowResizeEvent } from '@/utils/util'
  46. export default {
  47. name: 'JModal',
  48. props: {
  49. title: String,
  50. // 可使用 .sync 修饰符
  51. visible: Boolean,
  52. // 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
  53. fullscreen: {
  54. type: Boolean,
  55. default: true
  56. },
  57. // 是否允许切换全屏(允许后右上角会出现一个按钮)
  58. switchFullscreen: {
  59. type: Boolean,
  60. default: true
  61. },
  62. // 点击确定按钮的时候是否关闭弹窗
  63. okClose: {
  64. type: Boolean,
  65. default: true
  66. },
  67. },
  68. data() {
  69. return {
  70. // 内部使用的 slots ,不再处理
  71. usedSlots: ['title'],
  72. // 实际控制是否全屏的参数
  73. innerFullscreen: this.fullscreen,
  74. }
  75. },
  76. computed: {
  77. // 一些未处理的参数或特殊处理的参数绑定到 a-modal 上
  78. _attrs() {
  79. let attrs = { ...this.$attrs }
  80. // 如果全屏就将宽度设为 100%
  81. if (this.innerFullscreen) {
  82. attrs['width'] = '100%'
  83. }
  84. return attrs
  85. },
  86. modalClass() {
  87. return {
  88. 'j-modal-box': true,
  89. 'fullscreen': this.innerFullscreen,
  90. 'no-title': this.isNoTitle,
  91. 'no-footer': this.isNoFooter,
  92. }
  93. },
  94. modalStyle() {
  95. let style = {}
  96. // 如果全屏就将top设为 0
  97. if (this.innerFullscreen) {
  98. style['top'] = '0'
  99. }
  100. return style
  101. },
  102. isNoTitle() {
  103. return !this.title && !this.allSlotsKeys.includes('title')
  104. },
  105. isNoFooter() {
  106. return this._attrs['footer'] === null
  107. },
  108. slotsKeys() {
  109. return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))
  110. },
  111. scopedSlotsKeys() {
  112. return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
  113. },
  114. allSlotsKeys() {
  115. return Object.keys(this.$slots).concat(Object.keys(this.$scopedSlots))
  116. },
  117. // 切换全屏的按钮图标
  118. fullscreenButtonIcon() {
  119. return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
  120. },
  121. },
  122. watch: {
  123. visible() {
  124. if (this.visible) {
  125. this.innerFullscreen = this.fullscreen
  126. }
  127. },
  128. innerFullscreen(val) {
  129. this.$emit('update:fullscreen', val)
  130. },
  131. },
  132. methods: {
  133. getClass(clazz) {
  134. return { ...getClass(this), ...clazz }
  135. },
  136. getStyle(style) {
  137. return { ...getStyle(this), ...style }
  138. },
  139. close() {
  140. this.$emit('update:visible', false)
  141. },
  142. handleOk() {
  143. if (this.okClose) {
  144. this.close()
  145. }
  146. },
  147. handleCancel() {
  148. this.close()
  149. },
  150. /** 切换全屏 */
  151. toggleFullscreen() {
  152. this.innerFullscreen = !this.innerFullscreen
  153. triggerWindowResizeEvent()
  154. },
  155. }
  156. }
  157. </script>
  158. <style lang="less">
  159. .j-modal-box {
  160. &.fullscreen {
  161. top: 0;
  162. left: 0;
  163. padding: 0;
  164. // 兼容1.6.2版本的antdv
  165. & .ant-modal {
  166. top: 0;
  167. padding: 0;
  168. height: 100vh;
  169. }
  170. & .ant-modal-content {
  171. height: 100vh;
  172. border-radius: 0;
  173. & .ant-modal-body {
  174. /* title 和 footer 各占 55px */
  175. height: calc(100% - 55px - 55px);
  176. overflow: auto;
  177. }
  178. }
  179. &.no-title, &.no-footer {
  180. .ant-modal-body {
  181. height: calc(100% - 55px);
  182. }
  183. }
  184. &.no-title.no-footer {
  185. .ant-modal-body {
  186. height: 100%;
  187. }
  188. }
  189. }
  190. .j-modal-title-row {
  191. .left {
  192. width: calc(100% - 56px - 56px);
  193. }
  194. .right {
  195. width: 56px;
  196. position: inherit;
  197. .ant-modal-close {
  198. right: 56px;
  199. color: rgba(0, 0, 0, 0.45);
  200. &:hover {
  201. color: rgba(0, 0, 0, 0.75);
  202. }
  203. }
  204. }
  205. }
  206. &.no-title{
  207. .ant-modal-header {
  208. padding: 0px 24px;
  209. border-bottom: 0px !important;
  210. }
  211. }
  212. }
  213. @media (max-width: 767px) {
  214. .j-modal-box.fullscreen {
  215. margin: 0;
  216. max-width: 100vw;
  217. }
  218. }
  219. </style>