JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.1.4/vue.global.prod.min.js"></script>
<div id="app">
<div
v-for="n in messages"
:key="n.id"
@click="delMessage(n)"
@mouseenter="delDeleteTimeout(n)"
@mouseleave="setDeleteTimeout(n)"
class="message"
>
#{{ n.id }}: {{ n.text }}
<div class="timer" :class="n.timeout ? 'active' : ''"></div>
</div>
</div>
CSS
.message {
border: 1px solid silver;
padding: 10px;
margin: 10px;
background: #ccc;
cursor: pointer;
position: relative;
}
.timer {
display: inline-block;
position: absolute;
width: 0;
height: 2px;
background: red;
left: 0;
bottom: 0;
}
.timer.active {
width: 100%;
animation: timer-active 5s linear;
}
@keyframes timer-active {
from {
width: 0;
}
to {
width: 100%;
}
}
JavaScript
Vue.createApp({
data: () => ({
ID: 0,
messages: [],
}),
methods: {
addMessage(text) {
const message = {
id: ++this.ID,
timeout: null,
text,
};
this.setDeleteTimeout(message);
this.messages.push(message);
},
delMessage(message) {
const index = this.messages.indexOf(message);
if (index !== -1) {
this.delDeleteTimeout(message);
this.messages.splice(index, 1);
}
},
setDeleteTimeout(message) {
message.timeout = setTimeout(this.delMessage, 5000, message);
},
delDeleteTimeout(message) {
clearTimeout(message.timeout);
message.timeout = null;
},
},
mounted() {
const addMessage = () => {
this.addMessage(Math.random().toString(16).slice(2));
setTimeout(addMessage, 1000 + Math.random() * 3000);
};
addMessage();
},
}).mount('#app');