index.ts 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import { inject, provide, ref } from 'vue'
  2. import type { Toast, ToastOptions } from './types'
  3. import { deepMerge } from '../common/util'
  4. /**
  5. * useToast 用到的key
  6. */
  7. const toastDefaultOptionKey = '__TOAST_OPTION__'
  8. // 默认模板
  9. export const defaultOptions: ToastOptions = {
  10. duration: 2000,
  11. show: false
  12. }
  13. const None = Symbol('None')
  14. export function useToast(selector: string = ''): Toast {
  15. const toastOptionKey = getToastOptionKey(selector)
  16. const toastOption = inject(toastOptionKey, ref<ToastOptions | typeof None>(None)) // toast选项
  17. if (toastOption.value === None) {
  18. toastOption.value = defaultOptions
  19. provide(toastOptionKey, toastOption)
  20. }
  21. let timer: ReturnType<typeof setTimeout> | null = null
  22. const createMethod = (toastOptions: ToastOptions) => {
  23. return (options: ToastOptions | string) => {
  24. return show(deepMerge(toastOptions, typeof options === 'string' ? { msg: options } : options) as ToastOptions)
  25. }
  26. }
  27. const show = (option: ToastOptions | string) => {
  28. const options = deepMerge(defaultOptions, typeof option === 'string' ? { msg: option } : option) as ToastOptions
  29. toastOption.value = deepMerge(options, {
  30. show: true
  31. }) as ToastOptions
  32. // 开始渲染,并在 duration ms之后执行清除
  33. timer && clearTimeout(timer)
  34. if (toastOption.value.duration && toastOption.value.duration > 0) {
  35. timer = setTimeout(() => {
  36. timer && clearTimeout(timer)
  37. close()
  38. }, options.duration)
  39. }
  40. }
  41. const loading = createMethod({
  42. iconName: 'loading',
  43. duration: 0,
  44. cover: true
  45. })
  46. const success = createMethod({
  47. iconName: 'success',
  48. duration: 1500
  49. })
  50. const error = createMethod({ iconName: 'error' })
  51. const warning = createMethod({ iconName: 'warning' })
  52. const info = createMethod({ iconName: 'info' })
  53. const close = () => {
  54. toastOption.value = { show: false }
  55. }
  56. return {
  57. show,
  58. loading,
  59. success,
  60. error,
  61. warning,
  62. info,
  63. close
  64. }
  65. }
  66. export const getToastOptionKey = (selector: string) => {
  67. return selector ? `${toastDefaultOptionKey}${selector}` : toastDefaultOptionKey
  68. }
  69. export const toastIcon = {
  70. success() {
  71. return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="2 2 44 44" width="48" height="48"><circle cx="24" cy="26" r="22" fill="#000" opacity=".1"/><circle cx="24" cy="24" r="20" fill="#34D19D" opacity=".4"/><circle cx="24" cy="24" r="16" fill="#34D19D"/><path d="M19 24l4 4 8-8" stroke="#FFF" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/></svg>'
  72. },
  73. warning() {
  74. return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="2 2 44 44" width="48" height="48"><circle cx="24" cy="26" r="22" fill="#000" opacity=".1"/><circle cx="24" cy="24" r="20" fill="#F0883A" opacity=".4"/><circle cx="24" cy="24" r="16" fill="#F0883A"/><rect x="22.5" y="14" width="3" height="12" fill="#FFF" rx="1.5"/><circle cx="24" cy="30" r="2" fill="#FFF"/></svg>'
  75. },
  76. info() {
  77. return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="2 2 44 44" width="48" height="48"><circle cx="24" cy="26" r="22" fill="#000" opacity=".1"/><circle cx="24" cy="24" r="20" fill="#909CB7" opacity=".4"/><circle cx="24" cy="24" r="16" fill="#909CB7"/><circle cx="24" cy="18" r="2" fill="#FFF"/><rect x="22.5" y="22" width="3" height="12" fill="#FFF" rx="1.5"/></svg>'
  78. },
  79. error() {
  80. return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="2 2 44 44" width="48" height="48"><circle cx="24" cy="26" r="22" fill="#000" opacity=".1"/><circle cx="24" cy="24" r="20" fill="#fa4350" opacity=".4"/><circle cx="24" cy="24" r="16" fill="#fa4350"/><path d="M18 18l12 12M30 18L18 30" stroke="#FFF" stroke-width="2.5" stroke-linecap="round"/></svg>'
  81. }
  82. }