質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Vue.js

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

847閲覧

vue.jsで複数要素のアコーディオンを実装したい

masa207

総合スコア22

Vue.js

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2018/08/17 00:20

解決したいこと

練習で議事録アプリを作ろうと思うのですが、
<i class="el-icon-edit" v-on:click="toggle"></i>をクリックすると
各リストの<div v-show="show">が一斉に開閉してしまします。
複数要素で実装出来ますでしょうか。
ご存知の方いらっしゃいましたらご教示頂けると幸いです。
よろしくお願い致します。

該当のソースコード

HTML

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <title>議事録帳</title> 6 <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> 7 <link rel="stylesheet" href="css/style.css"> 8</head> 9<body> 10 <div id="app"> 11 <header class="l-header"> 12 <div class="l-container"> 13 <h1>議事録帳 14 <span class="info">({{remaining.length / todos.length}})</span> 15 </h1> 16 </div> 17 </header> 18 <div class="l-container"> 19 <ul v-if="todos.length"> 20 <li v-for="(todo, index) in todos"> 21 <input type="checkbox" v-model="todo.isDone"> 22 <span class="textView" v-bind:class="todo.picked" v-bind:class="{done: todo.isDone}">{{ todo.title }}</span> 23 <div class="el-button-group"> 24 <button type="button" class="el-button el-button--primary"><i class="el-icon-edit" v-on:click="toggle"></i></button> 25 <button type="button" class="el-button el-button--primary"><i class="el-icon-delete" v-on:click="deleteItem"></i></button> 26 </div> 27 <div v-show="show"> 28 <input type="radio" id="p" value="p" v-model="todo.picked"> 29 <label for="p">p</label> 30 <input type="radio" id="h1" value="h1" v-model="todo.picked"> 31 <label for="h1">h1</label> 32 <input type="radio" id="h2" value="h2" v-model="todo.picked"> 33 <label for="h2">h2</label> 34 </div> 35 </li> 36 </ul> 37 <ul v-else> 38 <li>Nothing to do</li> 39 </ul> 40 <form v-on:submit.prevent="addItem"> 41 <div class="bottomArea"> 42 <el-row> 43 <el-col :span="2"><button type="button" class="el-button el-button--danger"><i class="el-icon-delete" v-on:click="purge"></i></button></el-col> 44 <el-col :span="19"><el-input v-model="newItem" placeholder="Please text" v-model="input"></el-input></el-col> 45 <el-col :span="2"><button type="submit" class="el-button el-button--primary"><i class="el-icon-edit-outline" v-on:click="purge"></i></button></el-col> 46 </el-row> 47 </div> 48 </form> 49 </div> 50 </div> 51 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 52 <script src="https://unpkg.com/element-ui/lib/index.js"></script> 53 <script src="http://unpkg.com/element-ui/lib/umd/locale/ja.js"></script> 54 <script src="js/common.js"></script> 55</body> 56</html>

javascript

1(function(){ 2 //'use strict'; 3 4 5 ELEMENT.locale(ELEMENT.lang.ja) 6 var vm = new Vue({ 7 el: '#app', 8 data: { 9 newItem: '', 10 todos: [], 11 show: false, 12 radio: 'p' 13 }, 14 watch: { 15 todos: { 16 handler: function() { 17 localStorage.setItem('todos', JSON.stringify(this.todos)) 18 }, 19 deep: true 20 } 21 }, 22 mounted: function() { 23 this.todos = JSON.parse(localStorage.getItem('todos')) || [] 24 }, 25 methods: { 26 addItem: function() { 27 var item = { 28 title: this.newItem, 29 isDone: false, 30 picked: 'p' 31 } 32 this.todos.push(item) 33 this.newItem = '' 34 }, 35 toggle: function() { 36 this.show = !this.show 37 }, 38 deleteItem: function(index){ 39 if(confirm('are you sure?')) { 40 this.todos.splice(index, 1) 41 } 42 }, 43 purge: function(index){ 44 if(!confirm('delete finished?')) { 45 return 46 } 47 this.todos = this.remaining 48 } 49 }, 50 computed: { 51 remaining: function() { 52 return this.todos.filter(function(todo){ 53 return !todo.isDone 54 }) 55 } 56 } 57 }) 58 59})();

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

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

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

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

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

guest

回答2

0

ベストアンサー

たぶんリアクティブにならなくて悲しいやつかなと思います。
toggleの部分を以下のようにしてみたらどうでしょう。

JavaScript

1toggle: function (index) { 2 this.show.splice(index, 1, !this.show[index]) 3},

参考
#配列から特定の値を検索して、それの値を変えたい

追記#2018.08.20

HTML

1 2<!DOCTYPE html> 3<html lang="ja"> 4 5<head> 6 <meta charset="UTF-8"> 7 <title>議事録帳</title> 8 <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> 9</head> 10 11<body> 12 <div id="app"> 13 <header class="l-header"> 14 <div class="l-container"> 15 <h1>議事録帳 16 <span class="info">({{remaining.length / todos.length}})</span> 17 </h1> 18 </div> 19 </header> 20 <div class="l-container"> 21 <ul v-if="todos.length"> 22 <li v-for="(todo, index) in todos"> 23 <input type="checkbox" v-model="todo.isDone"> 24 <span class="textView" v-bind:class="todo.picked" v-bind:class="{done: todo.isDone}">{{ todo.title }}</span> 25 <div class="el-button-group"> 26 <button type="button" class="el-button el-button--primary"><i class="el-icon-edit" v-on:click="toggle(index)"></i></button> 27 <button type="button" class="el-button el-button--primary"><i class="el-icon-delete" v-on:click="deleteItem"></i></button> 28 </div> 29 <div v-show="show[index]"> 30 <input type="radio" id="p" value="p" v-model="todo.picked"> 31 <label for="p">p</label> 32 <input type="radio" id="h1" value="h1" v-model="todo.picked"> 33 <label for="h1">h1</label> 34 <input type="radio" id="h2" value="h2" v-model="todo.picked"> 35 <label for="h2">h2</label> 36 </div> 37 </li> 38 </ul> 39 <ul v-else> 40 <li>Nothing to do</li> 41 </ul> 42 <form v-on:submit.prevent="addItem"> 43 <div class="bottomArea"> 44 <el-row> 45 <el-col :span="2"><button type="button" class="el-button el-button--danger"><i class="el-icon-delete" v-on:click="purge"></i></button></el-col> 46 <el-col :span="19"> 47 <el-input v-model="newItem" placeholder="Please text" v-model="input"></el-input> 48 </el-col> 49 <el-col :span="2"><button type="submit" class="el-button el-button--primary"><i class="el-icon-edit-outline" v-on:click="purge"></i></button></el-col> 50 </el-row> 51 </div> 52 </form> 53 <pre>{{show}}</pre> 54 <pre>{{todos}}</pre> 55 </div> 56 </div> 57 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 58 <script src="https://unpkg.com/element-ui/lib/index.js"></script> 59 <script src="http://unpkg.com/element-ui/lib/umd/locale/ja.js"></script> 60 <script src="js/common.js"></script> 61</body> 62 63</html>

JavaScript

1(function () { 2 //'use strict'; 3 4 5 ELEMENT.locale(ELEMENT.lang.ja) 6 var vm = new Vue({ 7 el: '#app', 8 data: { 9 newItem: '', 10 todos: [], 11 show: [], 12 radio: 'p' 13 }, 14 watch: { 15 todos: { 16 handler: function () { 17 localStorage.setItem('todos', JSON.stringify(this.todos)) 18 }, 19 deep: true 20 } 21 }, 22 mounted: function () { 23 this.todos = JSON.parse(localStorage.getItem('todos')) || [] 24 }, 25 methods: { 26 addItem: function () { 27 var item = { 28 title: this.newItem, 29 isDone: false, 30 picked: 'p' 31 } 32 this.todos.push(item) 33 this.show.push(false) 34 this.newItem = '' 35 }, 36 toggle: function (index) { 37 this.show.splice(index, 1, !this.show[index]) 38 }, 39 deleteItem: function (index) { 40 if (confirm('are you sure?')) { 41 this.todos.splice(index, 1) 42 } 43 }, 44 purge: function (index) { 45 if (!confirm('delete finished?')) { 46 return 47 } 48 this.todos = this.remaining 49 } 50 }, 51 computed: { 52 remaining: function () { 53 return this.todos.filter(function (todo) { 54 return !todo.isDone 55 }) 56 } 57 } 58 }) 59 60})();

投稿2018/08/17 10:56

編集2018/08/20 01:00
wanabeeee

総合スコア19

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

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

masa207

2018/08/17 14:55

ご回答、ありがとうございます。 toggle: function (index) { this.show.splice(index, 1, this.show[index] = !this.show[index]) }, ご教授いただいた内容で試してみました。trueとfalseのtoggleにならなかったので、上記の様にしてみましたが、0番目の要素はうまく動く様でしたが、1番目、2番目とも押すと0番目がアコーディオンになり、console.log(this.show.splice(index, 1, this.show[index] = !this.show[index]))してみるとlength:1のみとなっておりました。 勉強不足で申し訳ございません、
wanabeeee

2018/08/20 01:03

keisukehさんの回答にコメントにしたつもりができてませんでした。 showプロパティを配列にする対応と合わせて修正すれば動くかなと思います。 回答にソース全体を追記したので違いなどご確認ください。
masa207

2018/08/20 01:56

ご回答ありがとうございます。 無事に問題解決いたしました。
guest

0

シンプルな解決方法としては
・showプロパティを配列にしてデータの数だけfalseで初期化する。
[false, false, false, false, ...要素の数だけ]

・ボタンがクリックされた時にtoggle(index)というふうにtoggleメソッドに引数indexを与える。

・toggleメソッドでshow[index]を入れ替える。

こんな感じでどうでしょうか?

html

1<i class="el-icon-edit" v-on:click="toggle(index)">

javascript

1methods: { 2 toggle: function(index) { 3 this.show[index] = !this.show[index]; 4 }, 5}

投稿2018/08/17 04:51

編集2018/08/17 04:52
keisukeh

総合スコア657

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

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

masa207

2018/08/17 08:24 編集

ご回答いただき、ありがとうございます。 ご教授いただいた内容で試したところ、console.logエラーが出ず、うまくいったかと思ったのですが、dataがtrueにも関わらずfalseの状態(要素が表示)となっておりました。 試しに、<div v-show="show[index]">にしたところ、chromeの開発ツールでdataをtrueにしたところ、しっかりその場所のみ非表示になりました。あと一息と思いつつ、開発ツール上ではうまくいくものの、ボタンをクリックしてもdataが書き変わらない様でした。勉強不足で申し訳ありません。やり方が悪いのでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問