UModal.vue 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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. :destroyOnClose="destroyOnClose"
  10. :footer="null"
  11. >
  12. <!-- 这个slot指什么暂不清楚 -->
  13. <!-- <slot></slot> -->
  14. <!--标题必填-->
  15. <template slot="title">
  16. <a-row class="u-modal-title-row" type="flex" justify="space-between">
  17. <a-col class="left-title">
  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-col class="right-btn">
  24. <a-icon :type="isModalFull?'menu-unfold':'menu-fold'" @click="isModalFull = !isModalFull"/>
  25. <!-- <a-icon type="column-width" /> -->
  26. <a-icon :type="isContentFull?'pic-right':'pic-center'" @click="isContentFull = !isContentFull"/>
  27. <a-button type="primary" @click="handleOk">确定</a-button>
  28. <a-button @click="handleCancel">取消</a-button>
  29. </a-col>
  30. </a-row>
  31. </template>
  32. <!--没有设置标题-->
  33. <!-- <template v-else slot="title">
  34. <a-row class="u-modal-title-row" type="flex">
  35. <a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
  36. <a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
  37. </a-col>
  38. </a-row>
  39. </template> -->
  40. <!-- 处理 scopedSlots -->
  41. <!-- <template v-for="slotName of scopedSlotsKeys" :slot="slotName">
  42. <slot :name="slotName"></slot>
  43. </template> -->
  44. <!-- 处理 slots -->
  45. <!-- <template v-for="slotName of slotsKeys" v-slot:[slotName]> -->
  46. <!-- </template> -->
  47. <div class="u-dialog-content" :class="setContentStyle">
  48. <slot></slot>
  49. </div>
  50. </a-modal>
  51. </template>
  52. <script>
  53. import { getClass, getStyle } from '@/utils/props-util'
  54. import { triggerWindowResizeEvent } from '@/utils/util'
  55. import ModalDragMixins from './ModalDragMixins'
  56. export default {
  57. name: 'UModal',
  58. mixins: [ModalDragMixins],
  59. props: {
  60. // 内容填满显示
  61. contentFull: {
  62. type: Boolean,
  63. default: false
  64. },
  65. // 全屏显示
  66. modalFull: {
  67. type: Boolean,
  68. default: false
  69. },
  70. title: {
  71. type: String,
  72. default: '内容'
  73. },
  74. // 可使用 .sync 修饰符
  75. visible: Boolean,
  76. // 是否开启拖拽:暂时隐藏不需要
  77. // draggable: Boolean,
  78. // 是否全屏弹窗,当全屏时无论如何都会禁止 body 滚动。可使用 .sync 修饰符
  79. fullscreen: {
  80. type: Boolean,
  81. default: false
  82. },
  83. // 是否允许切换全屏(允许后右上角会出现一个按钮)
  84. // switchFullscreen: {
  85. // type: Boolean,
  86. // default: false
  87. // },
  88. // 点击确定按钮的时候是否关闭弹窗
  89. okClose: {
  90. type: Boolean,
  91. default: true
  92. },
  93. // 关闭时销毁弹窗内容
  94. destroyOnClose: {
  95. type: Boolean,
  96. default: true
  97. },
  98. },
  99. data() {
  100. return {
  101. // 内部使用的 slots ,不再处理
  102. usedSlots: ['title'],
  103. // 实际控制是否全屏的参数
  104. innerFullscreen: this.fullscreen,
  105. // 内容展现形式:居中活全屏
  106. isContentFull: null,
  107. isModalFull: false,
  108. }
  109. },
  110. computed: {
  111. // 一些未处理的参数或特殊处理的参数绑定到 a-modal 上
  112. _attrs() {
  113. let attrs = { ...this.$attrs }
  114. // 如果全屏就将宽度设为 100%
  115. if (this.innerFullscreen) {
  116. attrs['width'] = '100%'
  117. }
  118. return attrs
  119. },
  120. modalClass() {
  121. return {
  122. 'u-modal-box': true,
  123. 'fullscreen': this.innerFullscreen,
  124. // 'no-title': this.isNoTitle,
  125. 'no-footer': this.isNoFooter,
  126. 'modalFullcss': this.isModalFull,
  127. 'modalMarginLeft': !this.isModalFull
  128. }
  129. },
  130. modalStyle() {
  131. let style = {}
  132. // 如果全屏就将top设为 0
  133. if (this.innerFullscreen) {
  134. style['top'] = '0'
  135. }
  136. return style
  137. },
  138. // isNoTitle() {
  139. // return !this.title && !this.allSlotsKeys.includes('title')
  140. // },
  141. isNoFooter() {
  142. return this._attrs['footer'] === null
  143. },
  144. slotsKeys() {
  145. return Object.keys(this.$slots).filter(key => !this.usedSlots.includes(key))
  146. },
  147. scopedSlotsKeys() {
  148. return Object.keys(this.$scopedSlots).filter(key => !this.usedSlots.includes(key))
  149. },
  150. allSlotsKeys() {
  151. return Object.keys(this.$slots).concat(Object.keys(this.$scopedSlots))
  152. },
  153. // 切换全屏的按钮图标
  154. fullscreenButtonIcon() {
  155. return this.innerFullscreen ? 'fullscreen-exit' : 'fullscreen'
  156. },
  157. setContentStyle() {
  158. return this.isContentFull ? 'contentFullcss' : 'contentCenter'
  159. // return {
  160. // 'contentFull': this.isContentFull,
  161. // 'contentCenter': !this.isContentFull
  162. // }
  163. },
  164. },
  165. watch: {
  166. visible() {
  167. if (this.visible) {
  168. this.innerFullscreen = this.fullscreen
  169. }
  170. },
  171. innerFullscreen(val) {
  172. this.$emit('update:fullscreen', val)
  173. },
  174. // 内容填满显示
  175. contentFull: {
  176. handler(newV, oldV){
  177. console.log(newV, oldV)
  178. this.isContentFull = newV
  179. },
  180. immediate: true
  181. },
  182. modalFull: {
  183. handler(newV, oldV){
  184. console.log(newV, oldV)
  185. this.isModalFull = newV
  186. },
  187. immediate: true
  188. }
  189. },
  190. methods: {
  191. getClass(clazz) {
  192. return { ...getClass(this), ...clazz }
  193. },
  194. getStyle(style) {
  195. return { ...getStyle(this), ...style }
  196. },
  197. close() {
  198. // this.$emit('update:visible', false)
  199. },
  200. handleOk() {
  201. this.$emit('ok')
  202. // if (this.okClose) {
  203. // this.close()
  204. // }
  205. },
  206. handleCancel() {
  207. this.$emit('cancel')
  208. // this.close()
  209. },
  210. /** 切换全屏 */
  211. toggleFullscreen() {
  212. this.innerFullscreen = !this.innerFullscreen
  213. triggerWindowResizeEvent()
  214. // 开启拖拽后的特殊处理
  215. if (this.draggable) {
  216. // 全屏的时候禁止拖动
  217. if (this.innerFullscreen) {
  218. // 还原弹窗的位置为0,0
  219. this.setModalPosition(0, 0, false)
  220. this.dragSettings.headerEl.style.cursor = null
  221. } else {
  222. // 取消全屏的时候,将弹窗移动到上次记录的位置
  223. this.resetModalPosition()
  224. this.dragSettings.headerEl.style.cursor = 'move'
  225. }
  226. }
  227. },
  228. }
  229. }
  230. </script>
  231. <style lang="less">
  232. .u-modal-box {
  233. // 宽高
  234. .ant-modal{
  235. height: 100vh !important;
  236. padding: 0 !important;
  237. margin-right: 0;
  238. top: 0;
  239. .ant-modal-content{
  240. border-radius: 0;
  241. height: 100%;
  242. overflow: hidden;
  243. }
  244. // 弹窗头部
  245. .ant-modal-header{
  246. padding: 0;
  247. height: 60px;
  248. box-shadow: 0 2px 12px rgba(211, 211, 211, 0.65);
  249. position: relative;
  250. .ant-modal-title{
  251. height: 100%;
  252. }
  253. .u-modal-title-row {
  254. height: 100%;
  255. padding: 0 24px;
  256. .left-title{
  257. line-height: 60px;
  258. }
  259. .right-btn{
  260. display: flex;
  261. align-items: center;
  262. }
  263. // .left {
  264. // width: 50%;
  265. // }
  266. // .right {
  267. // width: 56px;
  268. // position: inherit;
  269. // .ant-modal-close {
  270. // right: 56px;
  271. // color: rgba(0, 0, 0, 0.45);
  272. // &:hover {
  273. // color: rgba(0, 0, 0, 0.75);
  274. // }
  275. // }
  276. // }
  277. }
  278. }
  279. // 内容区域
  280. .ant-modal-body{
  281. height: calc(100vh - 60px);
  282. padding: 0;
  283. overflow: auto;
  284. background: #f6faff;
  285. // background: #F5F7FA;
  286. }
  287. .u-dialog-content{
  288. padding: 25px;
  289. margin: 20px auto;
  290. background-color: #fff;
  291. box-shadow: 0 2px 16px rgba(0, 0, 0, 0.1);
  292. border-radius: 4px;
  293. }
  294. .contentFullcss{
  295. width: calc(100% - 40px);
  296. }
  297. .contentCenter{
  298. width: 992px;
  299. }
  300. .ant-modal-close{
  301. display: none;
  302. }
  303. // .ant-modal-header{
  304. // position: fixed;
  305. // top: 0;
  306. // right: 0;
  307. // left: 208px;
  308. // }
  309. // .ant-modal-body{
  310. // margin-top: 56px;
  311. // background: #fff;
  312. // }
  313. }
  314. // &.fullscreen {
  315. // top: 0;
  316. // left: 0;
  317. // padding: 0;
  318. // // 兼容1.6.2版本的antdv
  319. // & .ant-modal {
  320. // top: 0;
  321. // padding: 0;
  322. // height: 100vh;
  323. // }
  324. // & .ant-modal-content {
  325. // height: 100vh;
  326. // border-radius: 0;
  327. // & .ant-modal-body {
  328. // /* title 和 footer 各占 55px */
  329. // height: calc(100% - 55px - 55px);
  330. // overflow: auto;
  331. // }
  332. // }
  333. // &.no-title, &.no-footer {
  334. // .ant-modal-body {
  335. // height: calc(100% - 55px);
  336. // }
  337. // }
  338. // &.no-title.no-footer {
  339. // .ant-modal-body {
  340. // height: 100%;
  341. // }
  342. // }
  343. // }
  344. // &.no-title{
  345. // .ant-modal-header {
  346. // padding: 0px 24px;
  347. // border-bottom: 0px !important;
  348. // }
  349. // }
  350. }
  351. .modalFullcss{
  352. .ant-modal{
  353. width: 100vw !important;
  354. margin-left: 0;
  355. }
  356. }
  357. .modalMarginLeft{
  358. .ant-modal{
  359. width: calc(100vw - 208px) !important;
  360. margin-left: 208px;
  361. }
  362. }
  363. @media (max-width: 767px) {
  364. .u-modal-box.fullscreen {
  365. margin: 0;
  366. max-width: 100vw;
  367. }
  368. }
  369. </style>