简体   繁体   中英

VueJs - dynamic class in a loop

Every time I select a div element, I want only that element to change color. With my current code, when I click an element, it changes the color for all items using the variable color , but I don't know how to make only the selected element change color.

This is my code:

 <div class="row">        
   <div v-for="(item, index) in seatShows" :key="index">
     <div class="col-auto" @click="select(item)">
       <div class="icon icon-shape text-white" :class="[color]">
         <img src="/images/butaca2-lg.png" class="position-relative">
         <a class="text-white position-absolute"> {{item.id_seat}} </a>
       </div>
     </div>
   </div>    
 </div>

And this is my Vue Code:

export default {
  props: ['route'],
  data() {
    return {
      seatShows: this.route,
      color: 'bg-seat-empty',
    }
  },
  methods:{
    select(item) {
      this.color = 'bg-primary';
      console.log(item) ;
      return this.color;
    },
    sel(item) {
      console.log(item.status_ticket);
    }
  }
}

Well, you assign color class to all elements in a loop. So when you update it, all elements will have that color.

If you want each element to have a different color, then you can just add color property to each element and change it using a method:

<div v-for="(item, index) in seatShows" :key="index">
  <div class="col-auto" @click="select(item)" >
   <div class="icon icon-shape text-white" :class="[item.color]">
     ...
   </div>
  </div>
</div>    

seatShows: [
  {id: 0, title: 'item1', color: 'bg-seat-empty'},
  {id: 1, title: 'item2', color: 'bg-seat-empty'},
  {id: 2, title: 'item3', color: 'bg-seat-empty'}
]

...

methods: {
  getSeatShows() {
    // Get seatShows data
    // ...

    // Add property "color" to seatShows data 
    this.seatShows.forEach(element => { 
      if (element.status === 0) {
        element['color'] = 'bg-seat-empty'
      }
      else if (element.status === 1) {
        element['color'] = 'bg-seat-full'
      }      
    })
  },
  select(item) {
    // Method 1
    this.seatShows[item.id].color = item.color

    // Method 2 (can be used to find items by some other unique property)
    // let itemIndex = this.seatShows.findIndex(element => element.id === item.id)
    // this.seatShows[itemIndex].color = item.color
  }
}

Well since you are using Vue. I would suggest a more component oriented solution. Convert your inner div into a component:

<template>
  <div class="col-auto" @click="select(item)">
    <div class="icon icon-shape text-white" :class="[current]">
      <img src="/images/butaca2-lg.png" class="position-relative">
      <a class="text-white position-absolute">{{item.id_seat}}</a>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    defaultClass: { type: String, default: "bg-secondary" },
    isSelected: { type: Boolean, default: false },
    selectedClass: { type: String, default: "" },
    item: Object
  },
  computed: {
    current: function() {
      return this.isSelected ? this.selectedClass : this.defaultClass;
    }
  },
  methods: {
    select(item) {
      this.$emit("selected", item); // emit the selected item
    }
  }
};
</script>

And then use it like this:

<template>
  <div class="row">
    <div v-for="(item, index) in seatShows" :key="index">
      <Select
        selectedClass="bg-primary"
        v-on:selected="select(item)"
        :item="item"
        :isSelected="selectedItem === item"
      ></Select>
    </div>
  </div>
</template>

<script>
import Select from "./Select";
export default {
  components: {
    Select
  },
  props: ["route"],
  data() {
    return {
      seatShows: [
        { title: "item1", id_seat: "1" },
        { title: "item2", id_seat: "2" },
        { title: "item3", id_seat: "3" }
      ],
      selectedItem: null // provide a selected item
    };
  },
  methods: {
    select(item) {
      this.selectedItem = item; // when selected populate it
      console.log(item);

    }       
  }
};
</script>

Here is the sandbox

I don't know what is item so I would suggest to use your index to switch between classes:

<div class="row">        
   <div v-for="(item, index) in seatShows" :key="index">
     <div class="col-auto" @click="select(index)">
       <div class="icon icon-shape text-white" :class="index === currentIndex ? primary : empty">
         <img src="/images/butaca2-lg.png" class="position-relative">
         <a class="text-white position-absolute"> {{item.id_seat}} </a>
       </div>
     </div>
   </div>    
 </div>

And you component data:

export default {
  props: ['route'],
  data() {
    return {
      seatShows: this.route,
      empty: 'bg-seat-empty',
      primary: 'bg-primary',
      currentIndex: -1
    }
  },
  methods:{
    select(index) {
      this.currentIndex = index;
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM