Я составляю список элементов с помощью цикла v-for. У меня есть данные API с сервера.
items: [
{
foo: 'something',
number: 1
},
{
foo: 'anything',
number: 2
}
]
и мой шаблон:
<div v-for(item,index) in items @click=toggleActive>
{{ item.foo }}
{{ item.number }}
</div>
JS:
methods: {
toggleActive() {
//
}
}
Как переключить активный класс с помощью: class = {active: something}? P.S У меня нет логического значения в элементах

Вы можете попробовать реализовать что-то вроде:
<div
v-for = "(item, index) in items"
v-bind:key = "item.id" // or alternativelly use `index`.
v-bind:class = {'active': activeItem[item.id]}
@click = "toggleActive(item)"
>
JS:
data: () => ({
activeItem: {},
}),
methods: {
toggleActive(item) {
if (this.activeItem[item.id]) {
this.removeActiveItem(item);
return;
}
this.addActiveItem(item);
},
addActiveItem(item) {
this.activeItem = Object.assign({},
this.activeItem,
[item.id]: item,
);
},
removeActiveItem(item) {
delete this.activeItem[item.id];
this.activeItem = Object.assign({}, this.activeItem);
},
}
Работает некоррент. Когда я пытаюсь щелкнуть по другому элементу, предыдущий класс не привязан. Мне нужно выбрать несколько элементов, а при втором щелчке по элементу активный класс без привязки
this.activeItem недостаточно определен, а что такое "[item.id]: item" в методе addActiveItem?
Произошла опечатка. [item.id]: item - это, по сути, способ динамической установки ключа свойства в объекте. Это новая функция Javascript, представленная в версии ES6, которая называется Computed property names. Итак, если значение item.id равно, например, «fooText», объект будет выглядеть как { 'fooText': item }. Для дальнейшего чтения: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…stackoverflow.com/questions/2462800/…
У меня была такая же проблема, и хотя найти много полезной информации непросто, ее относительно просто реализовать. У меня есть список магазинов, которые соответствуют своего рода облаку тегов кликабельных кнопок. При щелчке по одному из них к ссылке добавляется «добавленный» класс. Разметка:
<div class = "col-sm-10">
<a href = "#" class = "tagCloud" v-for = "store in stores" v-on:click = "toggleAdd(store)" v-bind:class = "{ 'added': selectedStoreIds.indexOf(store.id) !== -1 }">{{ store.name }}</a>
</div>
И связанный скрипт (в данном случае TypeScript). toggleAdd добавляет или удаляет идентификатор магазина из selectedStoreIds, и класс обновляется автоматически:
new Vue({
el: "#productPage",
data: {
stores: [] as StoreModel[],
selectedStoreIds: [] as string[],
},
methods: {
toggleAdd(store: StoreModel) {
let idx = this.selectedStoreIds.indexOf(store.id);
if (idx !== -1) {
this.selectedStoreIds.splice(idx, 1);
} else {
this.selectedStoreIds.push(store.id);
}
},
async mounted () {
this.stores = await this.getStores(); // ajax request to retrieve stores from server
}
});
Марлон Баркарол отвечает очень помог мне решить эту проблему.
Это можно сделать в 2 этапа.
1) Создайте цикл v-for в родительском компоненте, например
<myComponent v-for = "item in itemsList"/>
data() {
return {
itemsList: ['itemOne', 'itemTwo', 'itemThree']
}
}
2) Создайте сам дочерний myComponent со всей необходимой логикой
<div :class = "someClass" @click = "toggleClass"></div>
data(){
return {
someClass: "classOne"
}
},
methods: {
toggleClass() {
this.someClass = "classTwo";
}
}
Таким образом, все элементы в цикле v-for будут иметь отдельную логику, не относящуюся к элементам-близнецам.
Я работал над проектом, и у меня было такое же требование, вот код:
Вы можете игнорировать CSS и выбрать логику vue :)
new Vue({
el: '#app',
data: {
items: [{ title: 'Finance', isActive: false }, { title: 'Advertisement', isActive: false }, { title: 'Marketing', isActive: false }],
},
})body{background:#161616}.p-wrap{color:#bdbdbd;width:320px;background:#161616;min-height:500px;border:1px solid #ccc;padding:15px}.angle-down svg{width:20px;height:20px}.p-card.is-open .angle-down svg{transform:rotate(180deg)}.c-card,.p-card{background:#2f2f2f;padding:10px;border-bottom:1px solid #666}.c-card{height:90px}.c-card:first-child,.p-card:first-child{border-radius:8px 8px 0 0}.c-card:first-child{margin-top:10px}.c-card:last-child,.p-card:last-child{border-radius:0 0 8px 8px;border-bottom:none}.p-title .avatar{background-color:#8d6e92;width:40px;height:40px;border-radius:50%}.p-card.is-open .p-title .avatar{width:20px;height:20px}.p-card.is-open{padding:20px 0;background-color:transparent}.p-card.is-open:first-child{padding:10px 0 20px}.p-card.is-open:last-child{padding:20px 0 0}.p-body{display:none}.p-card.is-open .p-body{display:block}.sec-title{font-size:12px;margin-bottom:10px}<script src = "https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel = "stylesheet" href = "https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity = "sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin = "anonymous">
<div id = "app" class = "p-5">
<div class = "p-wrap mx-auto">
<div class = "sec-title">NEED TO ADD SECTION TITLE HERE</div>
<div>
<div v-for = "(item, index) in items" v-bind:key = "index" class = "p-card" v-bind:class = "{'is-open': item.isActive}"
v-on:click = "item.isActive = !item.isActive">
<div class = "row p-title align-items-center">
<div class = "col-auto">
<div class = "avatar"></div>
</div>
<div class = "col pl-0">
<div class = "title">{{item.title}}</div>
</div>
<div class = "col-auto">
<div class = "angle-down">
<svg aria-hidden = "true" focusable = "false" data-prefix = "far" data-icon = "angle-down" role = "img"
xmlns = "http://www.w3.org/2000/svg" viewBox = "0 0 320 512"
class = "svg-inline--fa fa-angle-down fa-w-10 fa-3x">
<path fill = "currentColor"
d = "M151.5 347.8L3.5 201c-4.7-4.7-4.7-12.3 0-17l19.8-19.8c4.7-4.7 12.3-4.7 17 0L160 282.7l119.7-118.5c4.7-4.7 12.3-4.7 17 0l19.8 19.8c4.7 4.7 4.7 12.3 0 17l-148 146.8c-4.7 4.7-12.3 4.7-17 0z"
class = ""></path>
</svg>
</div>
</div>
</div>
<div class = "p-body">
<div class = "c-card"></div>
<div class = "c-card"></div>
<div class = "c-card"></div>
</div>
</div>
</div>
</div>
</div>
без перемещения элемента в отдельный компонент