Toast.svelte 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <script>
  2. import { createEventDispatcher } from 'svelte';
  3. import Loading from '../loading/Loading.svelte';
  4. import Icon from '../icon/Icon.svelte';
  5. import Mask from '../mask/Mask.svelte';
  6. import Transition from './Transition.svelte';
  7. export let message = ''; //提示内容 toast content
  8. export let visible = false; //是否显示 is show
  9. export let duration = 2000; //显示时间,ms show time,ms
  10. export let position = 'center'; //显示位置,center,top,bottom show position,center,top,bottom
  11. export let py = '0'; //top和bottom时距离顶部或底部的距离 top and bottom distance from top or bottom
  12. export let radius = 'base'; //圆角 radius
  13. export let useSlot = false; //是否使用slot is use slot
  14. export let transitionType = 'scale'; //出现动画类型,可选值:fade, fly,scale,slide,none transition type
  15. export let transitionParams = {}; //出现动画参数 show transition params
  16. export let outDuration = 0; //过渡动画退出时间 transition out duration
  17. export let zIndex = 1000; //z-index
  18. export let type = ''; //提示类型,success、error、warning、info、loading,不传则不显示图标 toast type,success,error,warning,info,loading
  19. export let mask = {}; //遮罩层参数 mask params
  20. export let loading = {}; //loading参数 loading params
  21. export let icon = {}; //图标参数 icon params
  22. export let clickable = false; //是否可点击穿透 is clickable
  23. export let dynamicFixed = true; //是否动态固定 is dynamic fixed
  24. const dispatch = createEventDispatcher(); //创建事件派发器 create event dispatcher
  25. $: {
  26. if (visible) {
  27. if (duration === 0) {
  28. //不自动关闭 not auto close
  29. } else {
  30. setTimeout(() => {
  31. visible = false;
  32. dispatch('close');
  33. }, duration);
  34. }
  35. } else {
  36. dispatch('open');
  37. }
  38. }
  39. const typeObj = {
  40. success: 'checkbox-circle',
  41. error: 'close-circle',
  42. warning: 'error-warning',
  43. info: 'information',
  44. };
  45. const positionClass = {
  46. center: ' justify-center',
  47. top: ' justify-start',
  48. bottom: ' justify-end',
  49. };
  50. const pyClass = {
  51. '0': ' py-0',
  52. '10': ' py-10',
  53. '20': ' py-20',
  54. '40': ' py-40',
  55. '60': ' py-60',
  56. '80': ' py-80',
  57. };
  58. const radiusClass = {
  59. base: ' rounded',
  60. full: ' rounded-full',
  61. none: ' rounded-none',
  62. sm: ' rounded-sm',
  63. md: ' rounded-md',
  64. lg: ' rounded-lg',
  65. xl: ' rounded-xl',
  66. '2xl': ' rounded-2xl',
  67. };
  68. //解决 Safari 和 Chrome 或其他浏览器滚动时工具栏隐藏与显示引发的窗口高度变化问题
  69. // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
  70. // let vh = window.innerHeight * 0.01;
  71. // // Then we set the value in the --vh custom property to the root of the document
  72. // document.documentElement.style.setProperty('--vh', `${vh}px`);
  73. // // We listen to the resize event
  74. // window.addEventListener('resize', () => {
  75. // // We execute the same script as before
  76. // let vh = window.innerHeight * 0.01;
  77. // document.documentElement.style.setProperty('--vh', `${vh}px`);
  78. // });
  79. $: innerHeight = window.innerHeight;
  80. if (dynamicFixed) {
  81. //解决 Safari 和 Chrome 或其他浏览器滚动时工具栏隐藏与显示引发的窗口高度变化问题
  82. // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
  83. window.addEventListener('resize', () => {
  84. innerHeight = window.innerHeight;
  85. });
  86. }
  87. </script>
  88. {#if visible}
  89. <Mask {visible} {clickable} opacity={0} {...mask} {outDuration} />
  90. {/if}
  91. {#if visible}
  92. <div
  93. class={`fixed w-screen h-screen inset-0 flex flex-col${positionClass[position] || positionClass['center']}${
  94. position === 'center' ? '' : pyClass[py] || pyClass['20']
  95. } w-full h-full${clickable ? ' pointer-events-none' : ''}`}
  96. style={`z-index:${zIndex};height:${innerHeight}px`}
  97. >
  98. <!-- height: calc(var(--vh, 1vh) * 100 - ${
  99. !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) ? 0 : 0
  100. }px); -->
  101. <Transition {visible} {transitionType} {transitionParams} {outDuration}>
  102. <div class="flex justify-center px-10">
  103. <div
  104. class={`inline-block bg-black/90 dark:bg-white/90 text-center p-4${
  105. radiusClass[radius] || radiusClass['base']
  106. } text-white dark:text-black`}
  107. >
  108. {#if useSlot}
  109. <slot />
  110. {:else}
  111. {#if type !== ''}
  112. <div class="mb-2">
  113. {#if type === 'loading'}
  114. <Loading inverse {...loading} />
  115. {:else}
  116. <Icon
  117. name={type === 'success' || type === 'error' || type === 'warning' || type === 'info'
  118. ? `ri-${typeObj[type]}-line`
  119. : type}
  120. size={30}
  121. {...icon}
  122. />
  123. {/if}
  124. </div>
  125. {/if}
  126. <div>
  127. {message}
  128. </div>
  129. {/if}
  130. </div>
  131. </div>
  132. </Transition>
  133. </div>
  134. {/if}