message.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { createVNode, render, type AppContext } from 'vue'
  2. import MessageComponent from '@/components/Message.vue'
  3. export interface MessageOptions {
  4. type?: 'info' | 'success' | 'warning' | 'error'
  5. title?: string
  6. message?: string
  7. duration?: number
  8. closable?: boolean
  9. ctx?: AppContext
  10. onClose?: () => void
  11. }
  12. export type MessageTypeOptions = Omit<MessageOptions, 'type' | 'message'>
  13. export interface MessageIntance {
  14. id: string
  15. close: () => void
  16. }
  17. export type MessageFn = (message: string, options?: MessageTypeOptions) => MessageIntance
  18. export interface Message {
  19. (options: MessageOptions): MessageIntance
  20. info: MessageFn
  21. success: MessageFn
  22. error: MessageFn
  23. warning: MessageFn
  24. closeAll: () => void
  25. _context?: AppContext | null
  26. }
  27. const instances: MessageIntance[] = []
  28. let wrap: HTMLDivElement | null = null
  29. let seed = 0
  30. const defaultOptions: MessageOptions = {
  31. duration: 3000,
  32. }
  33. const message: Message = (options: MessageOptions) => {
  34. const id = 'message-' + seed++
  35. const props = {
  36. ...defaultOptions,
  37. ...options,
  38. id,
  39. }
  40. if (!wrap) {
  41. wrap = document.createElement('div')
  42. wrap.className = 'message-wrap'
  43. wrap.style.cssText = `
  44. width: 100%;
  45. position: fixed;
  46. top: 0;
  47. left: 0;
  48. z-index: 6000;
  49. pointer-events: none;
  50. display: flex;
  51. flex-direction: column;
  52. box-sizing: border-box;
  53. padding: 15px;
  54. background-color: rgba(255, 255, 255, 0);
  55. transition: all 1s ease-in-out;
  56. align-items: center;
  57. `
  58. document.body.appendChild(wrap)
  59. }
  60. const vm = createVNode(MessageComponent, props, null)
  61. const div = document.createElement('div')
  62. vm.appContext = options.ctx || message._context || null
  63. vm.props!.onClose = options.onClose
  64. vm.props!.onDestroy = () => {
  65. if (wrap && wrap.childNodes.length <= 1) {
  66. wrap.remove()
  67. wrap = null
  68. }
  69. render(null, div)
  70. }
  71. render(vm, div)
  72. wrap.appendChild(div.firstElementChild!)
  73. const instance = {
  74. id,
  75. close: () => vm?.component?.exposed?.close(),
  76. }
  77. instances.push(instance)
  78. return instance
  79. }
  80. message.success = (msg: string, options?: MessageTypeOptions) => message({ ...options, type: 'success', message: msg })
  81. message.info = (msg: string, options?: MessageTypeOptions) => message({ ...options, type: 'info', message: msg })
  82. message.warning = (msg: string, options?: MessageTypeOptions) => message({ ...options, type: 'warning', message: msg })
  83. message.error = (msg: string, options?: MessageTypeOptions) => message({ ...options, type: 'error', message: msg })
  84. message.closeAll = function() {
  85. for (let i = instances.length - 1; i >= 0; i--) {
  86. instances[i].close()
  87. }
  88. }
  89. export default message