import { createVNode, render } from 'vue'
import toastTemplate from './index.vue'
export interface IProps {
message?: string
duration?: number
background?: string
fontColor?: string
className?: string
position?: string
}
const defaultOpt = {
duration: 1500,
}
export interface ResultParams {
clear?: () => void
}
const Toast = (options: IProps): ResultParams => {
const container = document.createElement('div')
container.classList.add('toast-warp')
const opt = { ...defaultOpt, ...options }
const vm = createVNode(toastTemplate, opt)
render(vm, container)
document.body.appendChild(container)
/* const innerClear = () => {
const dom = vm.el as HTMLDivElement
let diffTime: number = opt.duration - 500 > 500 ? opt.duration - 500 : 500
if (dom.querySelector('.ac-toast__value')) {
dom.querySelector('.ac-toast__value')?.classList.remove('slide-down')
const removeClassTimer = setTimeout(() => {
dom.querySelector('.ac-toast__value')?.classList.add('reomve')
clearTimeout(removeClassTimer)
}, diffTime)
const removeDomTimer = setTimeout(() => {
render(null, container)
document.body.removeChild(container)
clearTimeout(removeDomTimer)
}, opt.duration)
}
}*/
if (opt.duration > 0) {
const timer = setTimeout(() => {
clear()
clearTimeout(timer)
}, opt.duration)
}
return {
clear,
}
}
const destroyDom = (options: IProps) => {
const opt = { ...defaultOpt, ...options }
const toastWarp: any = document.querySelector('.toast-warp')
let diffTime: number = opt.duration - 500 > 500 ? opt.duration - 500 : 500
if (document.querySelector('.ac-toast__value')) {
document.querySelector('.ac-toast__value')?.classList.remove('slide-down')
const removeClassTimer = setTimeout(() => {
document.querySelector('.ac-toast__value')?.classList.add('reomve')
clearTimeout(removeClassTimer)
}, diffTime)
const removeDomTimer = setTimeout(() => {
render(null, toastWarp)
document.body.removeChild(toastWarp)
clearTimeout(removeDomTimer)
}, opt.duration)
}
}
const clear = () => destroyDom({})
export default Toast
export { clear }
<template>
<div
class="ac-toast"
:style="{ alignItems: position }"
:class="wrapClassName"
@click="forbidClick ? close() : ''"
>
<div
class="ac-toast__value slide-down"
:style="{ background: background, color: fontColor }"
:class="className"
>
{{ message }}
</div>
</div>
</template>
<script setup>
import Toast from '@/components/ac-toast/index.ts'
const props = defineProps({
message: {
type: String,
default: ''
},
duration: {
type: Number,
default: 1500
},
background: {
type: String,
default: 'rgb(8, 8, 8, 0.7)'
},
fontColor: {
type: String,
default: '#fff'
},
className: {
type: String,
default: ''
},
wrapClassName: {
type: String,
default: '11111'
},
position: {
type: String,
default: 'flex-start'
},
forbidClick: {
type: Boolean,
default: false
}
})
const iDuration = props.duration / 1000 + 's'
const close = () => {}
</script>
<style>
.ac-toast {
position: fixed;
top: 10px;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
}
.ac-toast__value {
max-width: 82%;
padding: 6px 10px;
border-radius: 4px;
text-align: center;
display: inline-block;
}
.slide-down {
animation: slide-down-in 0.5s;
}
.reomve {
/* animation: slide-up v-bind('iDuration') 1 ease-out forwards; */
animation: slide-up-out 0.5s 1 ease-in-out forwards;
}
@keyframes slide-up-out {
from {
transform: translateY(0);
opacity: 1;
}
to {
transform: translateY(-100%);
opacity: 0;
}
}
@keyframes slide-down-in {
0% {
opacity: 0;
transform: translateY(-100%);
}
100% {
opacity: 1;
transform: translateY(0%);
}
}
</style>
<script setup>
import Toast, { clear } from '@/components/ac-toast'
const testClick = () => {
const toast = Toast({
message: 'toast8',
duration: 500,
className: '9999'
})
// clear()
}
</script>