modal.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. import GlobalConfig from '../../v-x-e-table/src/conf'
  2. import vSize from '../../mixins/size'
  3. import XEUtils from 'xe-utils'
  4. import { UtilTools, DomTools, GlobalEvent } from '../../tools'
  5. export const allActivedModals = []
  6. export const msgQueue = []
  7. export default {
  8. name: 'VxeModal',
  9. mixins: [vSize],
  10. props: {
  11. value: Boolean,
  12. id: String,
  13. type: { type: String, default: 'modal' },
  14. loading: { type: Boolean, default: null },
  15. status: String,
  16. iconStatus: String,
  17. className: String,
  18. top: { type: [Number, String], default: () => GlobalConfig.modal.top },
  19. position: [String, Object],
  20. title: String,
  21. duration: { type: [Number, String], default: () => GlobalConfig.modal.duration },
  22. message: [String, Function],
  23. cancelButtonText: { type: String, default: () => GlobalConfig.modal.cancelButtonText },
  24. confirmButtonText: { type: String, default: () => GlobalConfig.modal.confirmButtonText },
  25. lockView: { type: Boolean, default: () => GlobalConfig.modal.lockView },
  26. lockScroll: Boolean,
  27. mask: { type: Boolean, default: () => GlobalConfig.modal.mask },
  28. maskClosable: { type: Boolean, default: () => GlobalConfig.modal.maskClosable },
  29. escClosable: { type: Boolean, default: () => GlobalConfig.modal.escClosable },
  30. resize: { type: Boolean, default: () => GlobalConfig.modal.resize },
  31. showHeader: { type: Boolean, default: () => GlobalConfig.modal.showHeader },
  32. showFooter: { type: Boolean, default: () => GlobalConfig.modal.showFooter },
  33. showZoom: { type: Boolean, default: null },
  34. dblclickZoom: { type: Boolean, default: () => GlobalConfig.modal.dblclickZoom },
  35. width: [Number, String],
  36. height: [Number, String],
  37. minWidth: { type: [Number, String], default: () => GlobalConfig.modal.minWidth },
  38. minHeight: { type: [Number, String], default: () => GlobalConfig.modal.minHeight },
  39. zIndex: Number,
  40. marginSize: { type: [Number, String], default: GlobalConfig.modal.marginSize },
  41. fullscreen: Boolean,
  42. remember: { type: Boolean, default: () => GlobalConfig.modal.remember },
  43. destroyOnClose: { type: Boolean, default: () => GlobalConfig.modal.destroyOnClose },
  44. showTitleOverflow: { type: Boolean, default: () => GlobalConfig.modal.showTitleOverflow },
  45. transfer: { type: Boolean, default: () => GlobalConfig.modal.transfer },
  46. storage: { type: Boolean, default: () => GlobalConfig.modal.storage },
  47. storageKey: { type: String, default: () => GlobalConfig.modal.storageKey },
  48. animat: { type: Boolean, default: () => GlobalConfig.modal.animat },
  49. size: { type: String, default: () => GlobalConfig.modal.size || GlobalConfig.size },
  50. beforeHideMethod: { type: Function, default: () => GlobalConfig.modal.beforeHideMethod },
  51. slots: Object,
  52. events: Object
  53. },
  54. data () {
  55. return {
  56. inited: false,
  57. visible: false,
  58. contentVisible: false,
  59. modalTop: 0,
  60. modalZindex: 0,
  61. zoomLocat: null,
  62. firstOpen: false
  63. }
  64. },
  65. computed: {
  66. isMsg () {
  67. return this.type === 'message'
  68. }
  69. },
  70. watch: {
  71. width () {
  72. this.recalculate()
  73. },
  74. height () {
  75. this.recalculate()
  76. },
  77. value (visible) {
  78. this[visible ? 'open' : 'close']()
  79. }
  80. },
  81. created () {
  82. if (this.storage && !this.id) {
  83. UtilTools.error('vxe.error.reqProp', ['modal.id'])
  84. }
  85. },
  86. mounted () {
  87. const { $listeners, events = {} } = this
  88. if (this.value) {
  89. this.open()
  90. }
  91. this.recalculate()
  92. if (this.escClosable) {
  93. GlobalEvent.on(this, 'keydown', this.handleGlobalKeydownEvent)
  94. }
  95. // 触发 inserted 事件
  96. const type = 'inserted'
  97. const params = { type, $modal: this, $event: { type } }
  98. if ($listeners.inserted) {
  99. this.$emit('inserted', params)
  100. } else if (events.inserted) {
  101. events.inserted.call(this, params)
  102. }
  103. },
  104. beforeDestroy () {
  105. const { $el } = this
  106. GlobalEvent.off(this, 'keydown')
  107. this.removeMsgQueue()
  108. if ($el.parentNode === document.body) {
  109. $el.parentNode.removeChild($el)
  110. }
  111. },
  112. render (h) {
  113. const { $scopedSlots, slots = {}, inited, vSize, className, type, resize, showZoom, animat, loading, status, iconStatus, showFooter, zoomLocat, modalTop, dblclickZoom, contentVisible, visible, title, message, lockScroll, lockView, mask, isMsg, showTitleOverflow, destroyOnClose } = this
  114. const defaultSlot = $scopedSlots.default || slots.default
  115. const footerSlot = $scopedSlots.footer || slots.footer
  116. const headerSlot = $scopedSlots.header || slots.header
  117. const titleSlot = $scopedSlots.title || slots.title
  118. const headerOns = {
  119. mousedown: this.mousedownEvent
  120. }
  121. if (showZoom && dblclickZoom && type === 'modal') {
  122. headerOns.dblclick = this.toggleZoomEvent
  123. }
  124. return h('div', {
  125. class: ['vxe-modal--wrapper', `type--${type}`, className || '', {
  126. [`size--${vSize}`]: vSize,
  127. [`status--${status}`]: status,
  128. 'is--animat': animat,
  129. 'lock--scroll': lockScroll,
  130. 'lock--view': lockView,
  131. 'is--resize': resize,
  132. 'is--mask': mask,
  133. 'is--maximize': zoomLocat,
  134. 'is--visible': contentVisible,
  135. 'is--active': visible,
  136. 'is--loading': loading
  137. }],
  138. style: {
  139. zIndex: this.modalZindex,
  140. top: modalTop ? `${modalTop}px` : null
  141. },
  142. on: {
  143. click: this.selfClickEvent
  144. }
  145. }, [
  146. h('div', {
  147. class: 'vxe-modal--box',
  148. on: {
  149. mousedown: this.boxMousedownEvent
  150. },
  151. ref: 'modalBox'
  152. }, [
  153. this.showHeader ? h('div', {
  154. class: ['vxe-modal--header', !isMsg && showTitleOverflow ? 'is--ellipsis' : ''],
  155. on: headerOns
  156. }, headerSlot ? (!inited || (destroyOnClose && !visible) ? [] : headerSlot.call(this, { $modal: this }, h)) : [
  157. titleSlot ? titleSlot.call(this, { $modal: this }, h) : h('span', {
  158. class: 'vxe-modal--title'
  159. }, title ? UtilTools.getFuncText(title) : GlobalConfig.i18n('vxe.alert.title')),
  160. showZoom ? h('i', {
  161. class: ['vxe-modal--zoom-btn', 'trigger--btn', zoomLocat ? GlobalConfig.icon.MODAL_ZOOM_OUT : GlobalConfig.icon.MODAL_ZOOM_IN],
  162. attrs: {
  163. title: GlobalConfig.i18n(`vxe.modal.zoom${zoomLocat ? 'Out' : 'In'}`)
  164. },
  165. on: {
  166. click: this.toggleZoomEvent
  167. }
  168. }) : null,
  169. h('i', {
  170. class: ['vxe-modal--close-btn', 'trigger--btn', GlobalConfig.icon.MODAL_CLOSE],
  171. attrs: {
  172. title: GlobalConfig.i18n('vxe.modal.close')
  173. },
  174. on: {
  175. click: this.closeEvent
  176. }
  177. })
  178. ]) : null,
  179. h('div', {
  180. class: 'vxe-modal--body'
  181. }, [
  182. status ? h('div', {
  183. class: 'vxe-modal--status-wrapper'
  184. }, [
  185. h('i', {
  186. class: ['vxe-modal--status-icon', iconStatus || GlobalConfig.icon[`MODAL_${status}`.toLocaleUpperCase()]]
  187. })
  188. ]) : null,
  189. h('div', {
  190. class: 'vxe-modal--content'
  191. }, defaultSlot ? (!inited || (destroyOnClose && !visible) ? [] : defaultSlot.call(this, { $modal: this }, h)) : UtilTools.getFuncText(message)),
  192. !isMsg ? h('div', {
  193. class: ['vxe-loading', {
  194. 'is--visible': loading
  195. }]
  196. }, [
  197. h('div', {
  198. class: 'vxe-loading--spinner'
  199. })
  200. ]) : null
  201. ]),
  202. showFooter ? h('div', {
  203. class: 'vxe-modal--footer'
  204. }, footerSlot ? (!inited || (destroyOnClose && !visible) ? [] : footerSlot.call(this, { $modal: this }, h)) : [
  205. type === 'confirm' ? h('vxe-button', {
  206. ref: 'cancelBtn',
  207. on: {
  208. click: this.cancelEvent
  209. }
  210. }, this.cancelButtonText || GlobalConfig.i18n('vxe.button.cancel')) : null,
  211. h('vxe-button', {
  212. ref: 'confirmBtn',
  213. props: {
  214. status: 'primary'
  215. },
  216. on: {
  217. click: this.confirmEvent
  218. }
  219. }, this.confirmButtonText || GlobalConfig.i18n('vxe.button.confirm'))
  220. ]) : null,
  221. !isMsg && resize ? h('span', {
  222. class: 'vxe-modal--resize'
  223. }, ['wl', 'wr', 'swst', 'sest', 'st', 'swlb', 'selb', 'sb'].map(type => {
  224. return h('span', {
  225. class: `${type}-resize`,
  226. attrs: {
  227. type: type
  228. },
  229. on: {
  230. mousedown: this.dragEvent
  231. }
  232. })
  233. })) : null
  234. ])
  235. ])
  236. },
  237. methods: {
  238. recalculate () {
  239. const { width, height } = this
  240. const modalBoxElem = this.getBox()
  241. modalBoxElem.style.width = width ? (isNaN(width) ? width : `${width}px`) : null
  242. modalBoxElem.style.height = height ? (isNaN(height) ? height : `${height}px`) : null
  243. return this.$nextTick()
  244. },
  245. selfClickEvent (evnt) {
  246. if (this.maskClosable && evnt.target === this.$el) {
  247. const type = 'mask'
  248. this.close(type)
  249. }
  250. },
  251. updateZindex () {
  252. const { zIndex, modalZindex } = this
  253. if (zIndex) {
  254. this.modalZindex = zIndex
  255. } else if (modalZindex < UtilTools.getLastZIndex()) {
  256. this.modalZindex = UtilTools.nextZIndex()
  257. }
  258. },
  259. closeEvent (evnt) {
  260. const type = 'close'
  261. this.$emit(type, { type, $modal: this, $event: evnt })
  262. this.close(type)
  263. },
  264. confirmEvent (evnt) {
  265. const type = 'confirm'
  266. this.$emit(type, { type, $modal: this, $event: evnt })
  267. this.close(type)
  268. },
  269. cancelEvent (evnt) {
  270. const type = 'cancel'
  271. this.$emit(type, { type, $modal: this, $event: evnt })
  272. this.close(type)
  273. },
  274. open () {
  275. const { $refs, events = {}, inited, duration, visible, isMsg, remember, showFooter } = this
  276. if (!inited) {
  277. this.inited = true
  278. if (this.transfer) {
  279. document.body.appendChild(this.$el)
  280. }
  281. }
  282. if (!visible) {
  283. if (!remember) {
  284. this.recalculate()
  285. }
  286. this.visible = true
  287. this.contentVisible = false
  288. this.updateZindex()
  289. allActivedModals.push(this)
  290. setTimeout(() => {
  291. this.contentVisible = true
  292. this.$nextTick(() => {
  293. if (showFooter) {
  294. const operBtn = $refs.confirmBtn || $refs.cancelBtn
  295. if (operBtn) {
  296. operBtn.focus()
  297. }
  298. }
  299. const type = ''
  300. const params = { type, $modal: this }
  301. if (events.show) {
  302. events.show.call(this, params)
  303. } else {
  304. this.$emit('input', true)
  305. this.$emit('show', params)
  306. }
  307. })
  308. }, 10)
  309. if (isMsg) {
  310. this.addMsgQueue()
  311. if (duration !== -1) {
  312. setTimeout(this.close, XEUtils.toNumber(duration))
  313. }
  314. } else {
  315. this.$nextTick(() => {
  316. const { firstOpen, fullscreen } = this
  317. if (!remember || !firstOpen) {
  318. this.updatePosition().then(() => {
  319. setTimeout(() => this.updatePosition(), 20)
  320. })
  321. }
  322. if (!firstOpen) {
  323. this.firstOpen = true
  324. if (this.hasPosStorage()) {
  325. this.restorePosStorage()
  326. } else if (fullscreen) {
  327. this.$nextTick(() => this.maximize())
  328. }
  329. }
  330. })
  331. }
  332. }
  333. },
  334. addMsgQueue () {
  335. if (msgQueue.indexOf(this) === -1) {
  336. msgQueue.push(this)
  337. }
  338. this.updateStyle()
  339. },
  340. removeMsgQueue () {
  341. if (msgQueue.indexOf(this) > -1) {
  342. XEUtils.remove(msgQueue, comp => comp === this)
  343. }
  344. this.updateStyle()
  345. },
  346. updateStyle () {
  347. this.$nextTick(() => {
  348. let offsetTop = 0
  349. msgQueue.forEach(comp => {
  350. offsetTop += XEUtils.toNumber(comp.top)
  351. comp.modalTop = offsetTop
  352. offsetTop += comp.$refs.modalBox.clientHeight
  353. })
  354. })
  355. },
  356. updatePosition () {
  357. return this.$nextTick().then(() => {
  358. const { marginSize, position } = this
  359. const modalBoxElem = this.getBox()
  360. const clientVisibleWidth = document.documentElement.clientWidth || document.body.clientWidth
  361. const clientVisibleHeight = document.documentElement.clientHeight || document.body.clientHeight
  362. const isPosCenter = position === 'center'
  363. const { top, left } = isPosCenter ? { top: position, left: position } : Object.assign({}, position)
  364. const topCenter = isPosCenter || top === 'center'
  365. const leftCenter = isPosCenter || left === 'center'
  366. let posTop = ''
  367. let posLeft = ''
  368. if (left && !leftCenter) {
  369. posLeft = isNaN(left) ? left : `${left}px`
  370. } else {
  371. posLeft = `${Math.max(marginSize, clientVisibleWidth / 2 - modalBoxElem.offsetWidth / 2)}px`
  372. }
  373. if (top && !topCenter) {
  374. posTop = isNaN(top) ? top : `${top}px`
  375. } else {
  376. posTop = `${Math.max(marginSize, clientVisibleHeight / 2 - modalBoxElem.offsetHeight / 2)}px`
  377. }
  378. modalBoxElem.style.top = posTop
  379. modalBoxElem.style.left = posLeft
  380. })
  381. },
  382. close (type) {
  383. const { events = {}, remember, visible, isMsg, beforeHideMethod } = this
  384. const params = { type, $modal: this }
  385. if (visible) {
  386. Promise.resolve(beforeHideMethod ? beforeHideMethod(params) : null).then((rest) => {
  387. if (!XEUtils.isError(rest)) {
  388. if (isMsg) {
  389. this.removeMsgQueue()
  390. }
  391. this.contentVisible = false
  392. if (!remember) {
  393. this.zoomLocat = null
  394. }
  395. XEUtils.remove(allActivedModals, item => item === this)
  396. setTimeout(() => {
  397. this.visible = false
  398. if (events.hide) {
  399. events.hide.call(this, params)
  400. } else {
  401. this.$emit('input', false)
  402. this.$emit('hide', params)
  403. }
  404. }, 200)
  405. }
  406. }).catch(e => e)
  407. }
  408. },
  409. handleGlobalKeydownEvent (evnt) {
  410. if (evnt.keyCode === 27) {
  411. const lastModal = XEUtils.max(allActivedModals, item => item.modalZindex)
  412. // 多个时,只关掉最上层的窗口
  413. if (lastModal) {
  414. setTimeout(() => {
  415. if (lastModal === this && lastModal.escClosable) {
  416. this.close()
  417. }
  418. }, 10)
  419. }
  420. }
  421. },
  422. getBox () {
  423. return this.$refs.modalBox
  424. },
  425. isMaximized () {
  426. return !!this.zoomLocat
  427. },
  428. maximize () {
  429. return this.$nextTick().then(() => {
  430. if (!this.zoomLocat) {
  431. const marginSize = this.marginSize
  432. const modalBoxElem = this.getBox()
  433. const { visibleHeight, visibleWidth } = DomTools.getDomNode()
  434. this.zoomLocat = {
  435. top: modalBoxElem.offsetTop,
  436. left: modalBoxElem.offsetLeft,
  437. width: modalBoxElem.offsetWidth + (modalBoxElem.style.width ? 0 : 1),
  438. height: modalBoxElem.offsetHeight + (modalBoxElem.style.height ? 0 : 1)
  439. }
  440. Object.assign(modalBoxElem.style, {
  441. top: `${marginSize}px`,
  442. left: `${marginSize}px`,
  443. width: `${visibleWidth - marginSize * 2}px`,
  444. height: `${visibleHeight - marginSize * 2}px`
  445. })
  446. this.savePosStorage()
  447. }
  448. })
  449. },
  450. revert () {
  451. return this.$nextTick().then(() => {
  452. const zoomLocat = this.zoomLocat
  453. if (zoomLocat) {
  454. const modalBoxElem = this.getBox()
  455. this.zoomLocat = null
  456. Object.assign(modalBoxElem.style, {
  457. top: `${zoomLocat.top}px`,
  458. left: `${zoomLocat.left}px`,
  459. width: `${zoomLocat.width}px`,
  460. height: `${zoomLocat.height}px`
  461. })
  462. this.savePosStorage()
  463. }
  464. })
  465. },
  466. zoom () {
  467. return this[this.zoomLocat ? 'revert' : 'maximize']().then(() => this.isMaximized())
  468. },
  469. toggleZoomEvent (evnt) {
  470. const { $listeners, zoomLocat, events = {} } = this
  471. const params = { type: zoomLocat ? 'revert' : 'max', $modal: this, $event: evnt }
  472. return this.zoom().then(() => {
  473. if ($listeners.zoom) {
  474. this.$emit('zoom', params)
  475. } else if (events.zoom) {
  476. events.zoom.call(this, params)
  477. }
  478. })
  479. },
  480. getPosition () {
  481. if (!this.isMsg) {
  482. const modalBoxElem = this.getBox()
  483. if (modalBoxElem) {
  484. return {
  485. top: modalBoxElem.offsetTop,
  486. left: modalBoxElem.offsetLeft
  487. }
  488. }
  489. }
  490. return null
  491. },
  492. setPosition (top, left) {
  493. if (!this.isMsg) {
  494. const modalBoxElem = this.getBox()
  495. if (XEUtils.isNumber(top)) {
  496. modalBoxElem.style.top = `${top}px`
  497. }
  498. if (XEUtils.isNumber(left)) {
  499. modalBoxElem.style.left = `${left}px`
  500. }
  501. }
  502. return this.$nextTick()
  503. },
  504. boxMousedownEvent () {
  505. const { modalZindex } = this
  506. if (allActivedModals.some(_vm => _vm.visible && _vm.modalZindex > modalZindex)) {
  507. this.updateZindex()
  508. }
  509. },
  510. mousedownEvent (evnt) {
  511. const { remember, storage, marginSize, zoomLocat } = this
  512. const modalBoxElem = this.getBox()
  513. if (!zoomLocat && evnt.button === 0 && !DomTools.getEventTargetNode(evnt, modalBoxElem, 'trigger--btn').flag) {
  514. evnt.preventDefault()
  515. const domMousemove = document.onmousemove
  516. const domMouseup = document.onmouseup
  517. const disX = evnt.clientX - modalBoxElem.offsetLeft
  518. const disY = evnt.clientY - modalBoxElem.offsetTop
  519. const { visibleHeight, visibleWidth } = DomTools.getDomNode()
  520. document.onmousemove = evnt => {
  521. evnt.preventDefault()
  522. const offsetWidth = modalBoxElem.offsetWidth
  523. const offsetHeight = modalBoxElem.offsetHeight
  524. const minX = marginSize
  525. const maxX = visibleWidth - offsetWidth - marginSize - 1
  526. const minY = marginSize
  527. const maxY = visibleHeight - offsetHeight - marginSize - 1
  528. let left = evnt.clientX - disX
  529. let top = evnt.clientY - disY
  530. if (left > maxX) {
  531. left = maxX
  532. }
  533. if (left < minX) {
  534. left = minX
  535. }
  536. if (top > maxY) {
  537. top = maxY
  538. }
  539. if (top < minY) {
  540. top = minY
  541. }
  542. modalBoxElem.style.left = `${left}px`
  543. modalBoxElem.style.top = `${top}px`
  544. }
  545. document.onmouseup = () => {
  546. document.onmousemove = domMousemove
  547. document.onmouseup = domMouseup
  548. if (remember && storage) {
  549. this.$nextTick(() => {
  550. this.savePosStorage()
  551. })
  552. }
  553. }
  554. }
  555. },
  556. dragEvent (evnt) {
  557. evnt.preventDefault()
  558. const { $listeners, marginSize, events = {}, remember, storage } = this
  559. const { visibleHeight, visibleWidth } = DomTools.getDomNode()
  560. const type = evnt.target.getAttribute('type')
  561. const minWidth = XEUtils.toNumber(this.minWidth)
  562. const minHeight = XEUtils.toNumber(this.minHeight)
  563. const maxWidth = visibleWidth
  564. const maxHeight = visibleHeight
  565. const modalBoxElem = this.getBox()
  566. const domMousemove = document.onmousemove
  567. const domMouseup = document.onmouseup
  568. const clientWidth = modalBoxElem.clientWidth
  569. const clientHeight = modalBoxElem.clientHeight
  570. const disX = evnt.clientX
  571. const disY = evnt.clientY
  572. const offsetTop = modalBoxElem.offsetTop
  573. const offsetLeft = modalBoxElem.offsetLeft
  574. const params = { type: 'resize', $modal: this }
  575. document.onmousemove = evnt => {
  576. evnt.preventDefault()
  577. let dragLeft
  578. let dragTop
  579. let width
  580. let height
  581. switch (type) {
  582. case 'wl':
  583. dragLeft = disX - evnt.clientX
  584. width = dragLeft + clientWidth
  585. if (offsetLeft - dragLeft > marginSize) {
  586. if (width > minWidth) {
  587. modalBoxElem.style.width = `${width < maxWidth ? width : maxWidth}px`
  588. modalBoxElem.style.left = `${offsetLeft - dragLeft}px`
  589. }
  590. }
  591. break
  592. case 'swst':
  593. dragLeft = disX - evnt.clientX
  594. dragTop = disY - evnt.clientY
  595. width = dragLeft + clientWidth
  596. height = dragTop + clientHeight
  597. if (offsetLeft - dragLeft > marginSize) {
  598. if (width > minWidth) {
  599. modalBoxElem.style.width = `${width < maxWidth ? width : maxWidth}px`
  600. modalBoxElem.style.left = `${offsetLeft - dragLeft}px`
  601. }
  602. }
  603. if (offsetTop - dragTop > marginSize) {
  604. if (height > minHeight) {
  605. modalBoxElem.style.height = `${height < maxHeight ? height : maxHeight}px`
  606. modalBoxElem.style.top = `${offsetTop - dragTop}px`
  607. }
  608. }
  609. break
  610. case 'swlb':
  611. dragLeft = disX - evnt.clientX
  612. dragTop = evnt.clientY - disY
  613. width = dragLeft + clientWidth
  614. height = dragTop + clientHeight
  615. if (offsetLeft - dragLeft > marginSize) {
  616. if (width > minWidth) {
  617. modalBoxElem.style.width = `${width < maxWidth ? width : maxWidth}px`
  618. modalBoxElem.style.left = `${offsetLeft - dragLeft}px`
  619. }
  620. }
  621. if (offsetTop + height + marginSize < visibleHeight) {
  622. if (height > minHeight) {
  623. modalBoxElem.style.height = `${height < maxHeight ? height : maxHeight}px`
  624. }
  625. }
  626. break
  627. case 'st':
  628. dragTop = disY - evnt.clientY
  629. height = clientHeight + dragTop
  630. if (offsetTop - dragTop > marginSize) {
  631. if (height > minHeight) {
  632. modalBoxElem.style.height = `${height < maxHeight ? height : maxHeight}px`
  633. modalBoxElem.style.top = `${offsetTop - dragTop}px`
  634. }
  635. }
  636. break
  637. case 'wr':
  638. dragLeft = evnt.clientX - disX
  639. width = dragLeft + clientWidth
  640. if (offsetLeft + width + marginSize < visibleWidth) {
  641. if (width > minWidth) {
  642. modalBoxElem.style.width = `${width < maxWidth ? width : maxWidth}px`
  643. }
  644. }
  645. break
  646. case 'sest':
  647. dragLeft = evnt.clientX - disX
  648. dragTop = disY - evnt.clientY
  649. width = dragLeft + clientWidth
  650. height = dragTop + clientHeight
  651. if (offsetLeft + width + marginSize < visibleWidth) {
  652. if (width > minWidth) {
  653. modalBoxElem.style.width = `${width < maxWidth ? width : maxWidth}px`
  654. }
  655. }
  656. if (offsetTop - dragTop > marginSize) {
  657. if (height > minHeight) {
  658. modalBoxElem.style.height = `${height < maxHeight ? height : maxHeight}px`
  659. modalBoxElem.style.top = `${offsetTop - dragTop}px`
  660. }
  661. }
  662. break
  663. case 'selb':
  664. dragLeft = evnt.clientX - disX
  665. dragTop = evnt.clientY - disY
  666. width = dragLeft + clientWidth
  667. height = dragTop + clientHeight
  668. if (offsetLeft + width + marginSize < visibleWidth) {
  669. if (width > minWidth) {
  670. modalBoxElem.style.width = `${width < maxWidth ? width : maxWidth}px`
  671. }
  672. }
  673. if (offsetTop + height + marginSize < visibleHeight) {
  674. if (height > minHeight) {
  675. modalBoxElem.style.height = `${height < maxHeight ? height : maxHeight}px`
  676. }
  677. }
  678. break
  679. case 'sb':
  680. dragTop = evnt.clientY - disY
  681. height = dragTop + clientHeight
  682. if (offsetTop + height + marginSize < visibleHeight) {
  683. if (height > minHeight) {
  684. modalBoxElem.style.height = `${height < maxHeight ? height : maxHeight}px`
  685. }
  686. }
  687. break
  688. }
  689. modalBoxElem.className = modalBoxElem.className.replace(/\s?is--drag/, '') + ' is--drag'
  690. if (remember && storage) {
  691. this.savePosStorage()
  692. }
  693. if ($listeners.zoom) {
  694. this.$emit('zoom', params)
  695. } else if (events.zoom) {
  696. events.zoom.call(this, params)
  697. }
  698. }
  699. document.onmouseup = () => {
  700. this.zoomLocat = null
  701. document.onmousemove = domMousemove
  702. document.onmouseup = domMouseup
  703. setTimeout(() => {
  704. modalBoxElem.className = modalBoxElem.className.replace(/\s?is--drag/, '')
  705. }, 50)
  706. }
  707. },
  708. getStorageMap (key) {
  709. const version = GlobalConfig.version
  710. const rest = XEUtils.toStringJSON(localStorage.getItem(key))
  711. return rest && rest._v === version ? rest : { _v: version }
  712. },
  713. hasPosStorage () {
  714. const { id, remember, storage, storageKey } = this
  715. return !!(remember && storage && this.getStorageMap(storageKey)[id])
  716. },
  717. restorePosStorage () {
  718. const { id, remember, storage, storageKey } = this
  719. if (remember && storage) {
  720. const posStorage = this.getStorageMap(storageKey)[id]
  721. if (posStorage) {
  722. const modalBoxElem = this.getBox()
  723. const [left, top, width, height, zoomLeft, zoomTop, zoomWidth, zoomHeight] = posStorage.split(',')
  724. if (left) {
  725. modalBoxElem.style.left = `${left}px`
  726. }
  727. if (top) {
  728. modalBoxElem.style.top = `${top}px`
  729. }
  730. if (width) {
  731. modalBoxElem.style.width = `${width}px`
  732. }
  733. if (height) {
  734. modalBoxElem.style.height = `${height}px`
  735. }
  736. if (zoomLeft && zoomTop) {
  737. this.zoomLocat = {
  738. left: zoomLeft,
  739. top: zoomTop,
  740. width: zoomWidth,
  741. height: zoomHeight
  742. }
  743. }
  744. }
  745. }
  746. },
  747. savePosStorage () {
  748. const { id, remember, storage, storageKey, zoomLocat } = this
  749. if (remember && storage) {
  750. const modalBoxElem = this.getBox()
  751. const posStorageMap = this.getStorageMap(storageKey)
  752. posStorageMap[id] = [
  753. modalBoxElem.style.left,
  754. modalBoxElem.style.top,
  755. modalBoxElem.style.width,
  756. modalBoxElem.style.height
  757. ].concat(zoomLocat ? [
  758. zoomLocat.left,
  759. zoomLocat.top,
  760. zoomLocat.width,
  761. zoomLocat.height
  762. ] : []).map(val => val ? XEUtils.toNumber(val) : '').join(',')
  763. localStorage.setItem(storageKey, XEUtils.toJSONString(posStorageMap))
  764. }
  765. }
  766. }
  767. }