/* Toast */
/* global Vue Toast */
;(function() {
'use strict'
window.Toast = function(options, duration) {
if (typeof options === 'string') {
options = { content: options }
}
// 参数
options = Object.assign({
content: '',
type: 'info',
}, options)
// 0时不会自动关闭 默认3s
options.duration = duration ?? options.duration ?? 3000
// 0时 closable默认打开
if (options.duration === 0 && options.closable == null) {
options.closable = true
}
const { createApp, h, ref, onMounted, Transition } = Vue
const rootContainer = document.createElement('div')
const app = createApp({
setup() {
const content = ref(options.content)
const type = ref(options.type)
const closable = ref(options.closable)
const visible = ref(false)
onMounted(() => {
visible.value = true
if (options.duration > 0) {
setTimeout(close, options.duration)
}
})
// export-api
const close = () => {
visible.value = false
}
// private-api
const onAfterLeave = () => {
app.unmount(rootContainer)
rootContainer.remove()
}
return {
content,
type,
closable,
visible,
close,
onAfterLeave,
}
},
render() {
const { visible, type, content, closable, close, onAfterLeave } = this
return h(Transition, { name: 'inject-toast-slide-fade', appear: true, onAfterLeave }, {
default: () => (
visible &&
h('div', { class: 'inject-toast' },
h('div', { class: ['inject-toast-content', `inject-toast-content--${type}`] }, {
default: () => [
h('div', { class: 'inject-toast-content-text', innerHTML: content }),
closable && h('button', { class: 'inject-toast-content-close', onClick: close }, '×'),
],
}),
)
),
})
},
})
const toast = app.mount(rootContainer)
insertElementInContainer(rootContainer)
return {
// 关闭
close: toast.close,
}
}
;['info', 'success', 'warning', 'error'].forEach(type => {
Toast[type] = function(options, duration) {
if (typeof options === 'string') {
options = { content: options }
}
options = {
...options,
type,
}
return Toast(options, duration)
}
})
function safeAppendElement(cb) {
document.body ? cb() : window.addEventListener('DOMContentLoaded', cb)
}
function insertElementInContainer(elememnt) {
function getContainer() {
const classname = 'inject-toast-container'
let containerEl = document.querySelector('.' + classname)
if (containerEl == null) {
containerEl = document.createElement('div')
containerEl.classList.add(classname)
document.body.appendChild(containerEl)
}
return containerEl
}
safeAppendElement(() => {
getContainer().appendChild(elememnt)
})
}
;(function addStyle() {
const styleEl = document.createElement('style')
styleEl.appendChild(document.createTextNode(`
.inject-toast-container {
position: fixed;
z-index: 99999;
top: 80px;
right: 0;
left: 0;
pointer-events: none;
text-align: center;
}
.inject-toast {
contain: content;
max-height: 100vh;
transition: all .3s ease-in-out;
}
|> {
pointer-events: auto;
display: inline-flex;
justify-content: center;
margin-bottom: 10px;
padding: 8px 16px;
max-width: 90vw;
font-size: 14px;
line-height: 1.5em;
border: 1px solid;
box-shadow: 0 2px 3px rgba(0,0,0,.1);
}
|>--info {
color: #2e8bf0;
background: #f0faff;
border-color: #d4eeff;
}
|>--success {
color: #19bf6c;
background: #edfff3;
border-color: #bbf2cf;
}
|>--warning {
color: #f90;
background: #fff9e6;
border-color: #ffe7a3;
}
|>--error {
color: #ed3f13;
background: #ffefe6;
border-color: #ffcfb8;
}
|>-text {
flex: auto;
}
|>-close {
flex: none;
width: 20px;
margin: 0 -8px 0 10px;
padding: 0;
font-size: 16px;
color: #ababab;
border: none;
background: transparent;
cursor: pointer;
}
/* 动画 */
.inject-toast-slide-fade-enter-active,
.inject-toast-slide-fade-leave-active {
transition: all .3s;
}
.inject-toast-slide-fade-enter-from {
transform: translateY(-50%);
opacity: 0;
}
.inject-toast-slide-fade-leave-to {
transform: translateY(50%);
max-height: 0;
padding: 0;
opacity: 0;
}
`.replace(/\|>/g, '.inject-toast-content')))
document.head.appendChild(styleEl)
})()
// eslint-disable-next-line semi
})();