🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Q&A

解決済

1回答

3419閲覧

vue.js 選択したボタンの色を変更したい

alpaca540

総合スコア18

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

0グッド

0クリップ

投稿2020/11/22 05:20

編集2020/11/23 09:38

前提・実現したいこと

下記のような「お気に入り登録」機能をつくりたいと思っています。

お気に入りに登録したら、ボタンの色を灰色(デフォルト)→赤に変更したいのですが
すべてのボタンの色が変更となってしまいます。

下記のような動作を実現する方法をご教示いただければ幸いです。
よろしくお願いいたします。
(1)選択したアイテムのボタンの色のみを変更したいです。
(2)お気に入り(favorites)から削除した場合は、ボタンの色を赤→灰色に戻したいです。

イメージ説明

css

1.active{ 2 color: red; 3}

js

1Vue.component ('item-list', { 2 template: ` 3 <div> 4 // アイテム一覧 5 <section class="flex"> 6 <ul class="flex__list"> 7 <li class="flex__item246" v-for="item in items" v-bind:key="item.id" > 8 <img v-bind:src="item.img"> 9 <p>{{ item.name }}</p> 10 11 // ↓ ボタンを押すと、お気に入り一覧(favorites)に格納 12 <button v-on:click="addfavorites(item.id)" v-bind:class ={active:isActive}><i class="far fa-heart"></i></button> 13 </li> 14 </ul> 15 </section> 16 17 18     // お気に入り一覧 19 <section class="flex"> 20 <p>My favorites</p> 21 <ul class="flex__list"> 22 <li class="flex__item246" v-for="(item, index) in favorites" v-bind:key="item.id" > 23 <img v-bind:src="item.img"> 24 <p>{{ item.name }}</p> 25 26 // ↓ ボタンを押すと、お気に入り一覧(favorites)から削除 27 <button @click="delfavorites(index)" v-bind:class ={active:isActive}><i class="far fa-trash-alt"></i></button> 28 </li> 29 </ul> 30 </section> 31 </div> 32 `, 33 data: function(){ 34 return { 35 "items": [ 36 { "id": 0, "name": "アイテムA", "img": "image/items/a.jpg" }, 37 { "id": 1, "name": "アイテムB", "img": "image/items/b.jpg" }, 38 ], 39 favorites: [], 40 isActive: false, 41 } 42 }, 43 44 45 methods:{ 46 addfavorites: function (id) { 47 var selecteditem = this.items.find(function(item) { 48 return (item.id === id); 49 }); 50 let existence = false; 51 52 this.favorites.forEach(item => { 53 if(item.id === selecteditem.id){ 54 existence = true; 55 alert("登録済みです") 56 } 57 }) 58 if( existence === false){ 59 this.isActive = !this.isActive; 60 this.favorites.push(selecteditem) 61 } 62 }, 63 64 delfavorites: function (id) { 65 this.favorites.splice(id, 1) 66 } , 67 } 68 });

試したこと

v-bind:key="item.id"でボタンも個別に変更できるかと思ったのですが、他のボタンも変わってしまいます

(11/23修正)neko_daisuki様のご回答を参考に修正したコードです。

html

1<!DOCTYPE html> 2<head> 3 <meta charset="UTF-8"> 4 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 5 <script src="https://www.promisejs.org/polyfills/promise-7.0.4.min.js"></script> 6 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> 7 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 8 9 <link rel="stylesheet" media="all" type="text/css" href="css/destyle.css" /> 10 <link rel="stylesheet" media="all" type="text/css" href="css/flex.css"> 11 <link rel="stylesheet" media="all" type="text/css" href="css/search.css"> 12 13 14 <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet"> 15 16 17<title>SEARCH</title> 18<style> 19 .active{ 20 color: red; 21 } 22</style> 23 24</head> 25 26 27<body> 28 <div id="container"> 29<br> 30 <div id="app"> 31 <item-list></item-list> 32 </div><!-- app --> 33 34</div><!-- container --> 35 36 37<script src="js/flowers.js"></script> 38<script src="js/main.js"></script> 39 40 41 42</body> 43</html>

js

1var app = new Vue ({ 2 el: "#app", 3});

js

1Vue.component ('item-list', { 2 template: ` 3 <div> 4 5 <section class="flex"> 6 <ul class="flex__list"> 7 <li class="flex__item246" v-for="item in items" v-bind:key="item.id" > 8 <img v-bind:src="item.img"> 9 <p class="white">{{ item.anotherword }}</p> 10 <p>{{ item.name }}</p> 11 12 <button v-on:click="addfavorites(item.id)" v-bind:class ="{active: isActive(item.id)}"><i class="far fa-heart"></i></button> 13 14 </li> 15 </ul> 16 17 </section> 18 19 <section class="flex"> 20 <p>My favorites</p> 21 <ul class="flex__list"> 22 <li class="flex__item246" v-for="(item, index) in favorites" v-bind:key="item.id" > 23 <img v-bind:src="item.img"> 24 <p>{{ item.name }}</p> 25 26 <button @click="delfavorites(index)" v-bind:class ="{active: isActive(item.id)}"><i class="far fa-trash-alt"></i></button> 27 </li> 28 </ul> 29 30 </section> 31 </div> 32 `, 33 data: function(){ 34 return { 35 "items": [ 36 { "id": 0, "name": "アイテムA", "img": "image/items/a.jpg" }, 37 { "id": 1, "name": "アイテムB", "img": "image/items/b.jpg" }, 38 ], 39 favorites: [], 40 41 } 42 }, 43 methods:{ 44 addfavorites: function (id) { 45 var selecteditem = this.items.find(function(item) { 46 return (item.id === id); 47 }); 48 let existence = false; 49 50 this.favorites.forEach(item => { 51 if(item.id === selecteditem.id){ 52 existence = true; 53 alert("登録済みです") 54 } 55 }) 56 if( existence === false){ 57 this.favorites.push(selecteditem) 58 } 59 }, 60 delfavorites: function (id) { 61 this.favorites.splice(id, 1) 62 } , 63 isActive: function (id) { 64 return !!this.favorites.find(function (favo) { 65 return favo === id 66 }) 67 } 68 } 69 });

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ループ内で同じ変数(isActive)を参照しているのでそうなります。

1.itemをcomponentに切り出し、それぞれにisActiveをもたせる
2.isActiveをメソッドにして都度計算する

などが考えられますが、ここでは2の方法で実現してみます。

data の isActive を削除

isActiveメソッドを追加

methods: { isActive: function (id) { return !!this.favorites.find(function (favo) { return favo === id }) } }

テンプレート書き換え

<button v-on:click="addfavorites(item.id)" v-bind:class ={active: isActive(item.id)}>
<button @click="delfavorites(index)" v-bind:class ={active: isActive(item.id)}>

参考
https://jsfiddle.net/9ycq6r18/

投稿2020/11/22 09:10

neko_daisuki

総合スコア2090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alpaca540

2020/11/22 12:12

ご回答ありがとうございます!! 現在確認できる環境にいないため、明日確認させていただきます。 ご回答くださったのに、すぐに確認できず本当に申し訳ありません。
alpaca540

2020/11/23 05:48

改めましてご回答、そして参考のコードをありがとうございました。 回答くださいましたコードで実行してみたところ、 Error in render: "TypeError: isActive is not a function"というエラーが出たため、 isActiveメソッドをcolorChangeメソッドと名前を変更し実行してみたのですが ボタンの色を変更できませんでした。 参考コードをもとにもう少し考えてみたいと思っておりますが もし可能でしたら下記のコードはどのような意味なのか 教えていただけますでしょうか。 return !!this.favorites.find(function (favo) { return favo === id favorites配列の中で、favoとidが同じである最初の要素だったらtrueを返す・・? 初歩的な質問をすみません。。 お気に入り保存機能を実装させたくて、 javascriptが曖昧なまま、vue.jsに手をつけてしまいましたが 無理があった様です。
neko_daisuki

2020/11/23 07:27

methodsをふたつ定義していませんか? 以下は間違い methods: {  addfavorites ...  delfavorites ... }, methods: {  isActive ... }, 以下のようにします methods: {  addfavorites ...  delfavorites ...  isActive ... }, find は配列の中のマッチする最初の要素を返します。 マッチしない場合はundefined を返します。 var numbers = [1, 2, 3, 4, 5] var ret = numbers.find(function (i) { return i === 3 }) console.log(ret) // 3 !! は boolean(true or false) を返すためのイディオムです。 console.log(!!true) // true console.log(!!undefined) // false console.log(!!3) // true console.log(!!"neko") // true なので、favoritesにidが見つかればtrue見つからなければfalseを返します。 // 今回はfavoritesの中身が数値なので以下でも良かったです // this.favorites.includes(id)
alpaca540

2020/11/23 09:39

ありがとうございます!! (1)methods isActiveの件、失礼いたしました。下記の2点で解決いたしました。 ・v-bind:class ={active: isActive(item.id)}をv-bind:class ="{active: isActive(item.id)}"に変更 ・addfavorites内のthis.isActive = !this.isActive;を削除。 (2)findと!!の件、詳しくご説明くださりありがとうございます。 おかげさまで理解できました!! 「favoritesにidが見つかればtrue見つからなければfalseを返します」とのことで 修正しましたコードで問題ないかと思ったのですが、色が変更しません。。 何度もお聞きして大変厚かましく申し訳ないのですが、上記に修正したコードを記載させていただきました。 もし何かお気付きの点がありましたら教えていただければ幸いです。
neko_daisuki

2020/11/23 10:35

ごめんなさい。favoritesにはオブジェクトが入るんでしたね。 こちらでテストしたときに数値にして勘違いしました。 オブジェクトとID(数値)を比較してもfalseになるので、全部falseになってしまっています。 favoの後ろに.idを付けてください。 isActive: function (id) { return !!this.favorites.find(function (favo) { return favo.id === id }) } https://jsfiddle.net/p3feqhrx/
alpaca540

2020/11/23 12:49

ありがとうございます!無事できました! 理解できたつもりでしたが、favoがオブジェクトということに気付けず、 今後はこの要素の型が何なのかをまず確認致します。 この度は何度も丁寧にご説明下さいまして 本当に本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問