Toast

Toast或Toast[type] 调用

目前为 2020-12-05 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/411093/876846/Toast.js

  1. /* Toast */
  2.  
  3. /* global Vue Toast */
  4.  
  5. ;(function() {
  6. 'use strict'
  7.  
  8. window.Toast = function(options, duration) {
  9. if (typeof options === 'string') {
  10. options = { content: options }
  11. }
  12. // 参数
  13. options = Object.assign({
  14. content: '',
  15. type: 'info',
  16. }, options)
  17. // 0时不会自动关闭 默认3s
  18. options.duration = duration ?? options.duration ?? 3000
  19. // 0时 closable默认打开
  20. if (options.duration === 0 && options.closable == null) {
  21. options.closable = true
  22. }
  23.  
  24. const { createApp, h, ref, onMounted, Transition } = Vue
  25. const rootContainer = document.createElement('div')
  26. const app = createApp({
  27. setup() {
  28. const content = ref(options.content)
  29. const type = ref(options.type)
  30. const closable = ref(options.closable)
  31. const visible = ref(false)
  32.  
  33. onMounted(() => {
  34. visible.value = true
  35. if (options.duration > 0) {
  36. setTimeout(close, options.duration)
  37. }
  38. })
  39. // export-api
  40. const close = () => {
  41. visible.value = false
  42. }
  43. // private-api
  44. const onAfterLeave = () => {
  45. app.unmount(rootContainer)
  46. rootContainer.remove()
  47. }
  48.  
  49. return {
  50. content,
  51. type,
  52. closable,
  53. visible,
  54. close,
  55. onAfterLeave,
  56. }
  57. },
  58. render() {
  59. const { visible, type, content, closable, close, onAfterLeave } = this
  60. return h(Transition, { name: 'inject-toast-slide-fade', appear: true, onAfterLeave }, {
  61. default: () => (
  62. visible &&
  63. h('div', { class: 'inject-toast' },
  64. h('div', { class: ['inject-toast-content', `inject-toast-content--${type}`] }, {
  65. default: () => [
  66. h('div', { class: 'inject-toast-content-text', innerHTML: content }),
  67. closable && h('button', { class: 'inject-toast-content-close', onClick: close }, '×'),
  68. ],
  69. }),
  70. )
  71. ),
  72. })
  73. },
  74. })
  75.  
  76. const toast = app.mount(rootContainer)
  77. insertElementInContainer(rootContainer)
  78.  
  79. return {
  80. // 关闭
  81. close: toast.close,
  82. }
  83. }
  84.  
  85. ;['info', 'success', 'warning', 'error'].forEach(type => {
  86. Toast[type] = function(options, duration) {
  87. if (typeof options === 'string') {
  88. options = { content: options }
  89. }
  90. options = {
  91. ...options,
  92. type,
  93. }
  94. return Toast(options, duration)
  95. }
  96. })
  97.  
  98. function safeAppendElement(cb) {
  99. document.body ? cb() : window.addEventListener('DOMContentLoaded', cb)
  100. }
  101.  
  102. function insertElementInContainer(elememnt) {
  103. function getContainer() {
  104. const classname = 'inject-toast-container'
  105. let containerEl = document.querySelector('.' + classname)
  106. if (containerEl == null) {
  107. containerEl = document.createElement('div')
  108. containerEl.classList.add(classname)
  109. document.body.appendChild(containerEl)
  110. }
  111. return containerEl
  112. }
  113. safeAppendElement(() => {
  114. getContainer().appendChild(elememnt)
  115. })
  116. }
  117.  
  118. ;(function addStyle() {
  119. const styleEl = document.createElement('style')
  120. styleEl.appendChild(document.createTextNode(`
  121. .inject-toast-container {
  122. position: fixed;
  123. z-index: 99999;
  124. top: 80px;
  125. right: 0;
  126. left: 0;
  127. pointer-events: none;
  128. text-align: center;
  129. }
  130. .inject-toast {
  131. contain: content;
  132. max-height: 100vh;
  133. transition: all .3s ease-in-out;
  134. }
  135. |> {
  136. pointer-events: auto;
  137. display: inline-flex;
  138. justify-content: center;
  139. margin-bottom: 10px;
  140. padding: 8px 16px;
  141. max-width: 90vw;
  142. font-size: 14px;
  143. line-height: 1.5em;
  144. border: 1px solid;
  145. box-shadow: 0 2px 3px rgba(0,0,0,.1);
  146. }
  147. |>--info {
  148. color: #2e8bf0;
  149. background: #f0faff;
  150. border-color: #d4eeff;
  151. }
  152. |>--success {
  153. color: #19bf6c;
  154. background: #edfff3;
  155. border-color: #bbf2cf;
  156. }
  157. |>--warning {
  158. color: #f90;
  159. background: #fff9e6;
  160. border-color: #ffe7a3;
  161. }
  162. |>--error {
  163. color: #ed3f13;
  164. background: #ffefe6;
  165. border-color: #ffcfb8;
  166. }
  167. |>-text {
  168. flex: auto;
  169. }
  170. |>-close {
  171. flex: none;
  172. width: 20px;
  173. margin: 0 -8px 0 10px;
  174. padding: 0;
  175. font-size: 16px;
  176. color: #ababab;
  177. border: none;
  178. background: transparent;
  179. cursor: pointer;
  180. }
  181.  
  182. /* 动画 */
  183. .inject-toast-slide-fade-enter-active,
  184. .inject-toast-slide-fade-leave-active {
  185. transition: all .3s;
  186. }
  187. .inject-toast-slide-fade-enter-from {
  188. transform: translateY(-50%);
  189. opacity: 0;
  190. }
  191. .inject-toast-slide-fade-leave-to {
  192. transform: translateY(50%);
  193. max-height: 0;
  194. padding: 0;
  195. opacity: 0;
  196. }
  197. `.replace(/\|>/g, '.inject-toast-content')))
  198. document.head.appendChild(styleEl)
  199. })()
  200. // eslint-disable-next-line semi
  201. })();