Vue.js добавьте несколько активных классов в v-для cicle

#javascript #vue.js

Вопрос:

У меня есть несколько li элементов в v-for цикле. Мне нужно выбрать несколько одновременно и, если они уже выбраны, удалить active класс.

Мой скрипт работает, если я выбираю элементы по порядку: от первого до последнего (для выбора элементов), от последнего до первого (для отмены выбора элементов). Пожалуйста, помогите мне.

 var example1 = new Vue({
  el: '#example-1',
  data: {
    tags: ['tag-1', 'tag-2', 'tag-3', 'tag-4'],
    activeTag: [],
  },
  methods: {
    onTagClick: function(i) {
      if ( this.activeTag.includes(i) ) {
        console.log('Delete');
        const index = this.activeTag.indexOf(i);
        if ( index > -1 ) {
            this.activeTag.splice(index, 1);
        }
      } else {          
        console.log('Add');          
        this.activeTag.push(i);
      }
      console.log(`activeTag[i]: ${this.activeTag}`);
    }
  }
}) 
 li {
  display: inline-block;
  padding: 8px 10px;
  margin-right: 0.5rem;
}

a {
color: #000;
  text-decoration: none;
}

li.active>a{
  color: red;
} 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<div id="example-1">
  <ul v-if="tags">
    <li v-for="(tag, i) in tags" :key="i" :class="{active: activeTag[i] === i}">
        <a @click="onTagClick(i)"  href="javascript:void(0)">{{ tag }}</a>
    </li>
</ul>
</div> 

Комментарии:

1. Привет, мой ответ как-то помог ?

2. Привет @kissu, я использовал код Виниция и ваш совет для сопоставления массива. Большое спасибо

Ответ №1:

Что вы думаете об этом решении? Это самый короткий путь к достижению того же результата.

 var example1 = new Vue({
  el: '#example-1',
  data: {
    tags: [{tag:'tag-1', active: false},{tag:'tag-2', active: false}, {tag:'tag-3', active: false}, {tag:'tag-4', active: false} ],
    
  },
  methods: {
    onTagClick: function(i) {
       this.tags[i].active = !this.tags[i].active ;
    }
  }
}) 
 li {
  display: inline-block;
  padding: 8px 10px;
  margin-right: 0.5rem;
}

a {
color: #000;
  text-decoration: none;
}

li.active>a{
  color: red;
} 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<div id="example-1">
  <ul v-if="tags">
    <li v-for="(obj, i) in tags" :key="i" :class="{active: obj.active}" >
        <a @click="onTagClick(i)"  href="javascript:void(0)">{{ obj.tag }}</a>
    </li>
</ul> 

Ответ №2:

шаблон

 <li v-for="(tag, index) in tags" :key="index" :class="{active: tag.active}">
    <a href="#" @click.prevent="tag.active = !tag.active">{{ tag.name }}</a>
</li>
 

Скрипт

   computed: {
    checked(){ return this.tags.filter(tag => tag.active).map(tag => tag.name)}
  },
  data() {
    return {
      tags: [
        {name:'tag-1', active: false},
        {name:'tag-2', active: false},
        {name:'tag-3', active: false},
        {name:'tag-4', active: false}
      ]
    }
  }
 

Полный образец. Зацени это

 <template>
  <ul v-if="tags">
    <li v-for="(tag, index) in tags" :key="index" :class="{active: tag.active}">
      <a href="#" @click.prevent="tag.active = !tag.active">{{ tag.name }}</a>
    </li>
  </ul>
  <div>
    {{checked}}
  </div>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
  computed: {
    checked(){ return this.tags.filter(tag => tag.active).map(tag => tag.name)}
  },
  data() {
    return {
      tags: [
        {name:'tag-1', active: false},
        {name:'tag-2', active: false},
        {name:'tag-3', active: false},
        {name:'tag-4', active: false}
      ]
    }
  }
});
</script>
<style>
li {
  display: inline-block;
  padding: 8px 10px;
  margin-right: 0.5rem;
}

a {
color: #000;
  text-decoration: none;
}
li.active>a{
  color: red;
}
</style>
 

Комментарии:

1. Я не могу изменить структуру данных

2. @riky1 почему вы не можете изменить структуру данных ? Я не вижу никакой причины, по которой это невозможно.

3. Я получаю данные из базы данных, и они у меня есть props . Я ввел значения data() только для примера

4. Вы можете полностью получить эти значения из базы данных и помассировать ее. Проверьте мой обновленный ответ. Реквизиты или данные не имеют никакого значения, это все равно данные, которые вы можете изменить в своем компоненте, не так уж и важно.

Ответ №3:

Вот мое решение

 <template>
  <div>
    <span
      v-for="element in array"
      :key="element.id"
      :class="{ red: element.active }"
      @click="toggleSelection(element)"
    >
      {{ element.label }}
    </span>
  </div>
</template>

<script>
export default {
  data() {
    return {
      array: [
        { id: 1, label: 'tag1', active: false },
        { id: 2, label: 'tag2', active: false },
        { id: 3, label: 'tag3', active: false },
      ],
    }
  },
  methods: {
    toggleSelection(element) {
      const selectedElementIndex = this.array.findIndex((item) => item.id === element.id)
      this.array[selectedElementIndex].active = !this.array[selectedElementIndex].active
    },
  },
}
</script>

<style scoped>
.red {
  color: red;
}
</style>
 

Я по-прежнему настоятельно рекомендую обновить ваш массив и присвоить ему реальный уникальный идентификатор, а не передавать index :key его , что на самом деле делает противоположное тому, что он должен делать.

Чтобы создать удобный массив с хорошими ключами, вы можете использовать его на своем текущем tags :

 this.array = tags.map((tag, index) => ({id: index, label: tag, active: false}))
 

Вы можете вызвать этот метод, как только вы извлекли данные из API (в async created() хук), изменили их, а затем вставили в свой шаблон, следовательно, изменили структуру в более удобный формат.