最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Vue - Loop through an array of objects, and highlight the selected item on click - Stack Overflow

programmeradmin1浏览0评论

I have an array of objects which holds data, which I output to the DOM using map. Each item in the list, has a @click event listener. When you click on one of the items, I want it to be highlighted by way of adding a css class, for example ‘hover’. So basically it should work like a menu system. When you click on an item, that item is highlighted and the others should not be highlighted and vice versa.

The way i have it set up right now, all of the items in the list get highlighted, which is not the logic i’m trying to do. I have used console.log, to display which item has been clicked. However, I still have not figured out, how to make that selected item, the one thats highlighted instead of the whole list?

<template>
<div>
    <div>
        <h1>Dragonball</h1>
    </div>
    <div>
        <ul>
            <li v-for="(dragonBallFighters, index) of dragonBallFighter" @click="toggleClass(dragonBallFighters.id)" :key=dragonBallFighters.id :class="{hover: active}">
                <div class="dragonball-container">
                    <div class="dragonball-stats">
                    <h1>{{index}}, {{dragonBallFighters.name}}</h1>
                    <p>{{dragonBallFighters.race}}</p>
                    <p>{{dragonBallFighters.specialAttack}}</p>
                </div>
                <div class="dragonball-image">
                    <img :src="dragonBallFighters.img" :alt="dragonBallFighters.name" />
                </div>
                </div>
            </li>
        </ul>
    </div>
</div>
</template>

<script>
export default {
  data() {
    return {
      active: false,
      dragonBallFighter: [
        {
          id: 1,
          name: 'Goku',
          race: 'Sayain',
          specialAttack: 'Kamehameha Wave',
          img:
            '.52.28-AM.png'
        },
        {
          id: 2,
          name: 'Vegeta',
          race: 'Sayain',
          specialAttack: 'Final Flash',
          img:
            '.jpg'
        },
        {
          id: 3,
          name: 'Brolly',
          race: 'Sayain',
          specialAttack: 'Crusher Blast',
          img: '.png'
        },
        {
          id: 4,
          name: 'Majin Buu',
          race: 'Unknown',
          specialAttack: 'Absorbtion',
          img: '.jpg'
        },
        {
          id: 5,
          name: 'Janemba',
          race: 'Unknown',
          specialAttack: 'Teleportation Warp',
          img:
            '.png/revision/latest?cb=20140311163545'
        },
        {
          id: 6,
          name: 'Tien',
          race: 'Human',
          specialAttack: 'Tri Beam',
          img:
            '.dragonball.co/wp-content/uploads/2016/08/tien_banner.png?fit=704%2C396'
        },
        {
          id: 7,
          name: 'Vegito SSJB',
          race: 'Sayian',
          specialAttack: 'Final kamehameha',
          img:
            '/wp-content/uploads/2018/05/Vegito-Blue-SSGSS-Attack.png?fit=750%2C400&resize=750%2C400'
        },
        {
          id: 8,
          name: 'Toppo',
          race: 'Unknown',
          specialAttack: 'Finger Blasters',
          img: '.jpg'
        },
        {
          id: 9,
          name: 'Dyspo',
          race: 'Unknown',
          specialAttack: 'Super Hyper Lightspeed Mode',
          img:
            '.jpg'
        },
        {
          id: 10,
          name: 'Future Trunks',
          race: 'Human',
          specialAttack: 'Galick Gun',
          img:
            '.png'
        }
      ]
    };
  },
  methods: {
    toggleClass(id) {
      console.log('Clicked ' + id);

      const currentState = this.active;
      this.active = !currentState;
      //   this.selectedItemIndex = id;

      if (this.selectedItemIndex === id) {
        this.active === true;
      } else if (this.selectedItemIndex === !id) {
        this.active === false;
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.dragonball-container {
  cursor: pointer;
  display: grid;
  padding: 20px;
  grid-template-columns: 1fr 1fr;
  //background: #666;
  border: 2px solid #666;
  grid-gap: 20px;
  margin-bottom: 20px;
  border-radius: 10px;
  -webkit-box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
  -moz-box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
  box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
}

.dragonball-image img {
  display: grid;
  justify-content: center;
  align-items: center;
  width: 100%;
  max-width: 300px;
  border-radius: 100%;
}

ul li {
  list-style: none;
}
.hover {
  background: rgb(244, 244, 244);
  border-radius: 10px;
}
</style>

I have an array of objects which holds data, which I output to the DOM using map. Each item in the list, has a @click event listener. When you click on one of the items, I want it to be highlighted by way of adding a css class, for example ‘hover’. So basically it should work like a menu system. When you click on an item, that item is highlighted and the others should not be highlighted and vice versa.

The way i have it set up right now, all of the items in the list get highlighted, which is not the logic i’m trying to do. I have used console.log, to display which item has been clicked. However, I still have not figured out, how to make that selected item, the one thats highlighted instead of the whole list?

<template>
<div>
    <div>
        <h1>Dragonball</h1>
    </div>
    <div>
        <ul>
            <li v-for="(dragonBallFighters, index) of dragonBallFighter" @click="toggleClass(dragonBallFighters.id)" :key=dragonBallFighters.id :class="{hover: active}">
                <div class="dragonball-container">
                    <div class="dragonball-stats">
                    <h1>{{index}}, {{dragonBallFighters.name}}</h1>
                    <p>{{dragonBallFighters.race}}</p>
                    <p>{{dragonBallFighters.specialAttack}}</p>
                </div>
                <div class="dragonball-image">
                    <img :src="dragonBallFighters.img" :alt="dragonBallFighters.name" />
                </div>
                </div>
            </li>
        </ul>
    </div>
</div>
</template>

<script>
export default {
  data() {
    return {
      active: false,
      dragonBallFighter: [
        {
          id: 1,
          name: 'Goku',
          race: 'Sayain',
          specialAttack: 'Kamehameha Wave',
          img:
            'https://geeksnipper./wp-content/uploads/2018/03/Screen-Shot-2018-03-04-at-8.52.28-AM.png'
        },
        {
          id: 2,
          name: 'Vegeta',
          race: 'Sayain',
          specialAttack: 'Final Flash',
          img:
            'https://nerdreactor./wp-content/uploads/2018/01/vegeta-ssb.jpg'
        },
        {
          id: 3,
          name: 'Brolly',
          race: 'Sayain',
          specialAttack: 'Crusher Blast',
          img: 'http://media.icbook./2017/05/broly-995283-1280x0.png'
        },
        {
          id: 4,
          name: 'Majin Buu',
          race: 'Unknown',
          specialAttack: 'Absorbtion',
          img: 'https://i.ytimg./vi/50GF26RBWjw/maxresdefault.jpg'
        },
        {
          id: 5,
          name: 'Janemba',
          race: 'Unknown',
          specialAttack: 'Teleportation Warp',
          img:
            'https://vignette.wikia.nocookie/villainstournament/images/f/f1/Super_janemba.png/revision/latest?cb=20140311163545'
        },
        {
          id: 6,
          name: 'Tien',
          race: 'Human',
          specialAttack: 'Tri Beam',
          img:
            'http://i1.wp./www.dragonball.co/wp-content/uploads/2016/08/tien_banner.png?fit=704%2C396'
        },
        {
          id: 7,
          name: 'Vegito SSJB',
          race: 'Sayian',
          specialAttack: 'Final kamehameha',
          img:
            'http://i1.wp./shoryuken./wp-content/uploads/2018/05/Vegito-Blue-SSGSS-Attack.png?fit=750%2C400&resize=750%2C400'
        },
        {
          id: 8,
          name: 'Toppo',
          race: 'Unknown',
          specialAttack: 'Finger Blasters',
          img: 'https://i.ytimg./vi/_Lz9bTEL1dM/maxresdefault.jpg'
        },
        {
          id: 9,
          name: 'Dyspo',
          race: 'Unknown',
          specialAttack: 'Super Hyper Lightspeed Mode',
          img:
            'https://pre00.deviantart/5458/th/pre/f/2017/148/1/8/dragon_ball_super_dyspo_by_giuseppedirosso-dbaqm0s.jpg'
        },
        {
          id: 10,
          name: 'Future Trunks',
          race: 'Human',
          specialAttack: 'Galick Gun',
          img:
            'https://static5.icvine./uploads/original/11129/111290855/5809735-3904647274-14886.png'
        }
      ]
    };
  },
  methods: {
    toggleClass(id) {
      console.log('Clicked ' + id);

      const currentState = this.active;
      this.active = !currentState;
      //   this.selectedItemIndex = id;

      if (this.selectedItemIndex === id) {
        this.active === true;
      } else if (this.selectedItemIndex === !id) {
        this.active === false;
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.dragonball-container {
  cursor: pointer;
  display: grid;
  padding: 20px;
  grid-template-columns: 1fr 1fr;
  //background: #666;
  border: 2px solid #666;
  grid-gap: 20px;
  margin-bottom: 20px;
  border-radius: 10px;
  -webkit-box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
  -moz-box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
  box-shadow: 10px 10px 5px 0px rgba(240, 240, 240, 1);
}

.dragonball-image img {
  display: grid;
  justify-content: center;
  align-items: center;
  width: 100%;
  max-width: 300px;
  border-radius: 100%;
}

ul li {
  list-style: none;
}
.hover {
  background: rgb(244, 244, 244);
  border-radius: 10px;
}
</style>
Share Improve this question edited May 24, 2018 at 16:29 Andrew Baisden asked May 24, 2018 at 16:17 Andrew BaisdenAndrew Baisden 1611 gold badge5 silver badges17 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

My prefered way to do this is by adding a new key to each of the fighters and using that key in the v-for. The only thing needed in the markup is to change the :class value to be the active key in from the fighters in the v-for loop.

   <li
      v-for="(dragonBallFighters, index) of dragonBallFighter"
      @click="toggleClass(dragonBallFighters.id)"
      :key=dragonBallFighters.id
      :class="{hover: dragonBallFighters.active}"
   >
    <div class="dragonball-container">
      <div class="dragonball-stats">
        <h1>{{index}}, {{dragonBallFighters.name}}</h1>
        <p>{{dragonBallFighters.race}}</p>
        <p>{{dragonBallFighters.specialAttack}}</p>
      </div>
      <div class="dragonball-image">
        <img :src="dragonBallFighters.img" :alt="dragonBallFighters.name" />
      </div>
    </div>
  </li>

Then for the Javascript, we use Vue.set() to tell the dom that we added a key that is not in the original object that v-for is aware of. This makes vue correctly update the dom when we change the fighter's 'activeness'.

toggleClass(id) {
  // Create variable for all fighters (name takes up less space)
  let allFigthers = this.dragonBallFighter;
  // Get the clicked fighter
  let fighter = allFigthers.find(e => e.id === id)
  // Set all fighters to have a active key of false so that they "loose focus"
  allFigthers = allFigthers.map(e => Vue.set(e, 'active', false))
  // Use Vue.set to tell vue that we updated the object and it needs to be re-rendered
  Vue.set(fighter, 'active', !fighter.active)
}

Live example

The way I toggle the active class is simply by doing !fighter.active. This will be translated to not {boolean} ~ If the fighter.active is true then not true will equivalent in false. If it is false, not false will equivalent to true

Btw; I would suggest you to rename the object of fighters to dragonBallFighters. This way, the v-for makes more sense == <v-for="fighter in dragonBallFighters" One could translate that to

for each fighter in the dragonBallFighters object.

Per now, you are indirectly saying

for each dragonBallFighters in the dragonBallFighter object

witch doesn't float the same on the tongue ;)

Put "active" as a property of each dragonBall fighter and turn it on if it's clicked and turn the rest off.

The concept of Vue is to play with the data and let Vue take care of the UI :)

OR

rename "active" to activeID and set the ID of the clicked item to activeID and then apply hover only if activeID == item.id

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论