除了使用 Modal Dialog 通知 User 外,Toast Alert 亦為實務上常見的 UI。
Version
Vue 3.0.5
Tailwind CSS 2.1.1
Toast Alert
右側包含 dismiss button,且 5 秒鐘後也會自動 dismiss。
<template>
<button class="inline-flex items-center px-2.5 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" @click="onToggle">
Toggle
</button>
<transition enter-from-class="opacity-0" enter-active-class="transition duration-1000" enter-to-class="opacity-100" leave-from-class="opacity-100" leave-active-class="transition duration-1000" leave-to-class="opacity-0">
<div v-if="isShowAlert" class="rounded-md bg-green-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-green-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-green-800">
Successfully uploaded
</p>
</div>
<div class="ml-auto pl-3">
<div class="-mx-1.5 -my-1.5">
<button type="button" class="inline-flex bg-green-50 rounded-md p-1.5 text-green-500 hover:bg-green-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-green-50 focus:ring-green-600" @click="onDismiss">
<span class="sr-only">Dismiss</span>
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</button>
</div>
</div>
</div>
</div>
</transition>
</template>
<script setup>
ref: isShowAlert = false
let timeoutId = 0
let onToggle = () => {
isShowAlert = !isShowAlert
if (isShowAlert) timeoutId = setTimeout(() => isShowAlert = false, 5000)
else clearTimeout(timeoutId)
}
let onDismiss = () => {
isShowAlert = false
clearTimeout(timeoutId)
}
</script>
34 行
ref: isShowAlert = false
let timeoutId = 0
isShowAlert
:須與 HTML 溝通,故使用ref
宣告timeoutId
:只需與 JavaScript 溝通,故使用let
宣告即可
37 行
let onToggle = () => {
isShowAlert = !isShowAlert
if (isShowAlert) timeoutId = setTimeout(() => isShowAlert = false, 5000)
else clearTimeout(timeoutId)
}
當按下 Toggle
button 將執行 onToggle
:
- 對
isShowAlert
做 toggle - 若
isShowAlert
為true
,使用setTimeout()
在5
秒之後將isShowAlert
設定為false
- 若
isShowAlert
為false
,則使用clearTimeout()
取消
44 行
let onDismiss = () => {
isShowAlert = false
clearTimeout(timeoutId)
}
當按下 Toast alert 右側的 dismiss button 將執行 onDismiss
:
- 將
isShowAlert
設定為false
- 使用
clearTimeout()
取消
Function Pipeline
改用 Function Pipeline 方式實現。
<template>
<button class="inline-flex items-center px-2.5 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" @click="onToggle">
Toggle
</button>
<transition enter-from-class="opacity-0" enter-active-class="transition duration-1000" enter-to-class="opacity-100" leave-from-class="opacity-100" leave-active-class="transition duration-1000" leave-to-class="opacity-0">
<div v-if="isShowAlert" class="rounded-md bg-green-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-green-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
</div>
<div class="ml-3">
<p class="text-sm font-medium text-green-800">
Successfully uploaded
</p>
</div>
<div class="ml-auto pl-3">
<div class="-mx-1.5 -my-1.5">
<button type="button" class="inline-flex bg-green-50 rounded-md p-1.5 text-green-500 hover:bg-green-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-green-50 focus:ring-green-600" @click="onDismiss">
<span class="sr-only">Dismiss</span>
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</button>
</div>
</div>
</div>
</div>
</transition>
</template>
<script setup>
import { ref } from 'vue'
import { pipe, not, ifElse, always, thunkify } from 'ramda'
import { read, write } from 'vue3-fp'
let isShowAlert = ref(false)
let timeoutId = 0
let hideAlert = pipe(
always(false),
write(isShowAlert)
)
let onToggle = pipe(
read(isShowAlert),
not,
write(isShowAlert),
ifElse(
read(isShowAlert),
() => timeoutId = setTimeout(hideAlert, 5000),
thunkify(clearTimeout)(timeoutId)
)
)
let onDismiss = pipe(
always(false),
write(isShowAlert),
thunkify(clearTimeout)(timeoutId)
)
</script>
38 行
let isShowAlert = ref(false)
let timeoutId = 0
isShowAlert
:須與 HTML 溝通,故使用ref()
timeoutId
:只需與 JavaScript 溝通,故使用let
宣告即可
46 行
let onToggle = pipe(
read(isShowAlert),
not,
write(isShowAlert),
ifElse(
read(isShowAlert),
() => timeoutId = setTimeout(hideAlert, 5000),
thunkify(clearTimeout)(timeoutId)
)
)
當按下 Toggle
button 將執行 onToggle
:
read(isShowAlert)
:讀取isShowAlert
statenot()
:對isShowAlert
togglewrite(isShowAlert)
:寫入isShowAlert
stateifElse()
:若isShowAlert
為true
,使用setTimeout()
在5
秒之後將isShowAlert
設定為false
,反之則使用clearTimeout()
取消
41 行
let hideAlert = pipe(
always(false),
write(isShowAlert)
)
將 isShowAlert
state 設定為 false
。
57 行
let onDismiss = pipe(
always(false),
write(isShowAlert),
thunkify(clearTimeout)(timeoutId)
)
當按下 toast alert 右側的 dismiss button 將執行 onDismiss
:
always(false)
:準備false
write(isShowAlert)
:寫入isShowAlert
statethunkify(clearTimeout)(timeoutId)
:使用clearTimeout()
取消
Conclusion
- Toast alert 的 UI 來自於 Tailwind UI,自行控制
isShowAlert
state 顯示 toast alert