Message.vue 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <template>
  2. <Transition
  3. name="message-fade"
  4. appear
  5. mode="in-out"
  6. @beforeLeave="emit('close')"
  7. @afterLeave="emit('destroy')"
  8. >
  9. <div class="message" :id="id" v-if="visible">
  10. <div class="message-container"
  11. @mouseenter="clearTimer()"
  12. @mouseleave="startTimer()"
  13. >
  14. <div class="icons">
  15. <IconAttention theme="filled" size="18" fill="#faad14" v-if="type === 'warning'" />
  16. <IconCheckOne theme="filled" size="18" fill="#52c41a" v-if="type === 'success'" />
  17. <IconCloseOne theme="filled" size="18" fill="#ff4d4f" v-if="type === 'error'" />
  18. <IconInfo theme="filled" size="18" fill="#1677ff" v-if="type === 'info'" />
  19. </div>
  20. <div class="content">
  21. <div class="title" v-if="title">{{ title }}</div>
  22. <div class="description">{{ message }}</div>
  23. </div>
  24. <div class="control" v-if="closable">
  25. <span
  26. class="close-btn"
  27. @click="close()"
  28. >
  29. <IconCloseSmall />
  30. </span>
  31. </div>
  32. </div>
  33. </div>
  34. </Transition>
  35. </template>
  36. <script lang="ts" setup>
  37. import { onMounted, ref, onBeforeMount } from 'vue'
  38. import { icons } from '@/plugins/icon'
  39. const {
  40. IconAttention,
  41. IconCheckOne,
  42. IconCloseOne,
  43. IconInfo,
  44. IconCloseSmall,
  45. } = icons
  46. const props = withDefaults(defineProps<{
  47. id: string
  48. message: string
  49. type?: string
  50. title?: string
  51. duration?: number
  52. closable?: boolean
  53. }>(), {
  54. type: 'success',
  55. title: '',
  56. duration: 3000,
  57. closable: false,
  58. })
  59. const emit = defineEmits<{
  60. (event: 'close'): void
  61. (event: 'destroy'): void
  62. }>()
  63. const visible = ref(true)
  64. const timer = ref<number | null>(null)
  65. const startTimer = () => {
  66. if (props.duration <= 0) return
  67. timer.value = setTimeout(close, props.duration)
  68. }
  69. const clearTimer = () => {
  70. if (timer.value) clearTimeout(timer.value)
  71. }
  72. const close = () => visible.value = false
  73. onBeforeMount(() => {
  74. clearTimer()
  75. })
  76. onMounted(() => {
  77. startTimer()
  78. })
  79. defineExpose({
  80. close,
  81. })
  82. </script>
  83. <style lang="scss" scoped>
  84. .message {
  85. max-width: 600px;
  86. & + & {
  87. margin-top: 15px;
  88. }
  89. }
  90. .message-container {
  91. min-width: 50px;
  92. display: flex;
  93. align-items: center;
  94. padding: 10px;
  95. font-size: 13px;
  96. overflow: hidden;
  97. border-radius: 8px;
  98. box-shadow: 0 1px 8px rgba(0, 0, 0, .15);
  99. background: #fff;
  100. pointer-events: all;
  101. position: relative;
  102. .icons {
  103. display: flex;
  104. align-items: center;
  105. margin-right: 10px;
  106. }
  107. .title {
  108. font-size: 14px;
  109. font-weight: 700;
  110. overflow: hidden;
  111. text-overflow: ellipsis;
  112. white-space: nowrap;
  113. }
  114. .content {
  115. width: 100%;
  116. }
  117. .description {
  118. line-height: 1.5;
  119. color: #333;
  120. }
  121. .title + .description {
  122. margin-top: 5px;
  123. }
  124. .control {
  125. position: relative;
  126. height: 100%;
  127. margin-left: 10px;
  128. }
  129. .close-btn {
  130. font-size: 15px;
  131. color: #666;
  132. display: flex;
  133. align-items: center;
  134. cursor: pointer;
  135. &:hover {
  136. color: #1677ff;
  137. }
  138. }
  139. }
  140. .message-fade-enter-active {
  141. animation: message-fade-in-down .3s;
  142. }
  143. .message-fade-leave-active {
  144. animation: message-fade-out .3s;
  145. }
  146. @keyframes message-fade-in-down {
  147. 0% {
  148. opacity: 0;
  149. transform: translateY(-20px);
  150. }
  151. 100% {
  152. opacity: 1;
  153. transform: translateY(0);
  154. }
  155. }
  156. @keyframes message-fade-out {
  157. 0% {
  158. opacity: 1;
  159. margin-top: 0;
  160. }
  161. 100% {
  162. opacity: 0;
  163. margin-top: -45px;
  164. }
  165. }
  166. </style>