I'm working no an app that onclick shows a div. Now if someone clicks the button to open another div, I want to hide the previously opened div. So far I was able to get this functionality by manually setting this.movies[index].open = false
and this.movies[index].hideImg = true
however - if there were thousands of entries this would be impossible to solve with this solution. I'm talking about the toggle(id)
method
<template>
<div v-for="(movie, index) in movies" :key="index" >
<div >
<h3>{{ movie.name }}</h3>
<p >{{ movie.duration }}</p>
<button @click="toggle(movie.id)" >
<p v-if="movie.hideImg">►</p>
<p v-else>▼</p>
</button>
</div>
<div v-if="movie.open">
<video controls="controls" autoplay name="media">
<source
:src="require(`@/assets/movie${index 1}.mp4`)"
alt="video"
type="video/mp4"
width="500px"
autoplay
/>
</video>
</div>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
movies: [
{
name: "Windy Highway",
duration: "15 seconds",
hideImg: true,
open: false,
id: 1,
movieStart: "0:00",
movieMid: "0.08",
movieEnd: "0:15",
},
{
name: "Sunny Station",
duration: "32 seconds",
hideImg: true,
open: false,
id: 2,
movieStart: "0:00",
movieMid: "0.16",
movieEnd: "0:32",
},
{
name: "Abstract Material",
duration: "9 seconds",
hideImg: true,
open: false,
id: 3,
movieStart: "0:00",
movieMid: "0.05",
movieEnd: "0:09",
},
{
name: "Pumpkin Drilling",
duration: "17 seconds",
hideImg: true,
open: false,
id: 4,
movieStart: "0:00",
movieMid: "0.09",
movieEnd: "0:17",
},
],
};
},
methods: {
toggle(id) {
this.movies[0].open = false;
this.movies[1].open = false;
this.movies[2].open = false;
this.movies[3].open = false;
this.movies[0].hideImg = true;
this.movies[1].hideImg = true;
this.movies[2].hideImg = true;
this.movies[3].hideImg = true;
this.movies[id - 1].hideImg = !this.movies[id - 1].hideImg;
this.movies[id - 1].open = !this.movies[id - 1].open;
console.log(
this.movies[id - 1].movieStart,
"-",
this.movies[id - 1].movieMid,
"-",
this.movies[id - 1].movieEnd
);
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin: 60px auto 0;
}
.watchBtn {
background-color: red;
border-radius: 10px;
margin-left: 10px;
height: 20px;
display: flex;
align-items: center;
}
.watchBtn:hover {
background-color: rgb(255, 191, 107);
cursor: pointer;
}
.movieContainer {
margin: 5px auto;
display: flex;
flex-direction: column;
}
.center {
margin: 0 auto;
display: flex;
align-items: center;
}
.duration {
margin: 0 5px 0 10px;
}
.movieContainer video {
width: 500px;
}
</style>
here's StackBlitz
CodePudding user response:
...
toggle(id) {
this.movies.forEach(movie => { movie.open = false, movie.hideImg = true })
this.movies[id - 1].hideImg = false;
this.movies[id - 1].open = true;
},
...
I would also make the following changes:
- change
v-if
tov-show
, it's faster to show/hide DOM instead of adding/removing - Remove
hideImg
, and base all logic on a single valueopen
- save the current state, so you can close the currently open item again
<template>
<div v-for="(movie, index) in movies" :key="index" >
<div >
{{ movie.name }}
<button @click="toggle(movie.id)" >
<p v-show="!movie.open">►</p>