I have an array in which I put all the elements that have the class Box, then I add a new div with Vue, which is added correctly, but I try that the last div that I add appears with an opacity effect (I will change it for a better one), but the result is not the expected one.
What happens is that the new element is added, but the effect adds it to the previous one and I want that it is always in the new element that I add above all, that is to say, it would be the one of the index 0,
¿? What am I doing wrong?
html code:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Preguntas en vivo</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="app">
<div >
<div>
<input type="text" v-model="nuevoAutor"><br>
<input type="text" v-model="nuevaPregunta"><br>
<button @click="agregarMensaje">Agregar</button>
</div>
<div v-for="pregunta in preguntas">
{{pregunta.autor}}: {{pregunta.mensaje}}
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="js/vue.js"></script>
<script src="js/index.js"></script>
</body>
</html>
Vue code:
const app = new Vue({
el: "#app",
data: {
preguntas: [
],
preguntasAprobadas: [
],
nuevoAutor: "",
nuevaPregunta: "",
boxes: []
},
methods: {
agregarMensaje: function(){
this.preguntas.unshift({
autor: this.nuevoAutor,
mensaje: this.nuevaPregunta,
publicado: false
});
this.nuevaPregunta = "";
this.nuevoAutor = "";
boxes = document.querySelectorAll(".box");
this.agregarClase();
},
agregarClase: function(){
boxes[0].className = " animation";
}
}
})
css code:
.box {
width: 100%;
background-color: rgb(255, 224, 174);
border: 1px solid rgb(255, 210, 137);
padding: 20px;
margin-top: 30px;
min-height: 200px;
}
.animation {
animation: show 5s;
-webkit-animation: show 5s;
}
@keyframes show {
0% { opacity: 0; }
100% { opacity: 1; }
}
EDIT: I have simplified it, there is only one class, the div is added, with the class box, but it loads the style to the last one, that is, the one at the bottom, and not to the last one that is added.
.box {
background-color: rgb(255, 224, 174);
border: 1px solid rgb(255, 210, 137);
padding: 20px;
margin-top: 30px;
min-height: 200px;
width: 100%;
opacity: 1;
animation: show 1s;
-webkit-animation: show 1s;
}
@keyframes show {
0% {
width: 1%;
opacity: 0;
}
100% {
width: 100%;
opacity: 1;
}
}
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Preguntas en vivo</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div id="app">
<div >
<div>
<input type="text" v-model="nuevoAutor"><br>
<input type="text" v-model="nuevaPregunta"><br>
<button @click="agregarMensaje">Agregar</button>
</div>
<div v-for="pregunta in preguntas">
<div >
{{pregunta.autor}}: {{pregunta.mensaje}}
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="js/vue.js"></script>
<script src="js/index.js"></script>
</body>
</html>
CodePudding user response:
You're looking for the vue component transition-group
(see docs).
It's a component that adds css classes as the elements are added / removed / reordered, so it lets you animate them.
Here's an example:
<template>
<div id="app">
<transition-group name="fade" mode="in-out">
<div v-for="question of questions" :key="question.id" >
{{ question.msg }}
</div>
</transition-group>
<button @click="addQuestion">Add question</button>
</div>
</template>
<script>
export default {
data () {
return {
questions: [
{ id: 1, msg: 'Hey'},
{ id: 2, msg: 'there'},
{ id: 3, msg: 'General'},
{ id: 4, msg: 'Kenobi'},
],
}
},
methods: {
addQuestion () {
const newId = Math.floor(Math.random() * 1000 4)
const newQuestion = { id: newId, msg: 'New question' newId }
this.questions.push(newQuestion)
}
}
}
</script>
<style>
#app {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
gap: 16px;
max-width: 300px;
margin: 0 auto;
height: 80vh;
}
.questions {
display: flex;
flex-direction: column;
gap: 8px;
}
.questions .item {
background: #fafafa;
border: 1px solid lightgray;
text-align: center;
min-width: 130px;
padding: 4px 12px;
}
// Fade animation for each item
.item.fade-enter-active {
transition: opacity 1s;
}
.item.fade-enter, .item.fade-leave-to {
opacity: 0;
}
</style>
Every time you add an item (at the beginning, at the end, in the middle, it doesn't matter), it will have this css transition applied. Same for when they are removed (see fade-leave-to
class)
See example as CodePen