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

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

ただいまの
回答率

90.40%

  • JavaScript

    18136questions

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

  • Vue.js

    934questions

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

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

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 690

masa207

score 2

 解決したいこと

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

 該当のソースコード

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>議事録帳</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div id="app">
        <header class="l-header">
            <div class="l-container">
                <h1>議事録帳
                    <span class="info">({{remaining.length / todos.length}})</span>
                </h1>
            </div>
        </header>
        <div class="l-container">
            <ul v-if="todos.length">
                <li v-for="(todo, index) in todos">
                    <input type="checkbox" v-model="todo.isDone">
                    <span class="textView" v-bind:class="todo.picked" v-bind:class="{done: todo.isDone}">{{ todo.title }}</span>
                    <div class="el-button-group">
                        <button type="button" class="el-button el-button--primary"><i class="el-icon-edit" v-on:click="toggle"></i></button>
                        <button type="button" class="el-button el-button--primary"><i class="el-icon-delete" v-on:click="deleteItem"></i></button>
                    </div>
                    <div v-show="show">
                        <input type="radio" id="p" value="p" v-model="todo.picked">
                        <label for="p">p</label>
                        <input type="radio" id="h1" value="h1" v-model="todo.picked">
                        <label for="h1">h1</label>
                        <input type="radio" id="h2" value="h2" v-model="todo.picked">
                        <label for="h2">h2</label>
                    </div>
                </li>
            </ul>
            <ul v-else>
                <li>Nothing to do</li>
            </ul>
            <form v-on:submit.prevent="addItem">
                <div class="bottomArea">
                    <el-row>
                        <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>
                        <el-col :span="19"><el-input v-model="newItem" placeholder="Please text" v-model="input"></el-input></el-col>
                        <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>
                    </el-row>
                </div>
            </form>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="http://unpkg.com/element-ui/lib/umd/locale/ja.js"></script>
    <script src="js/common.js"></script>
</body>
</html>
(function(){
    //'use strict';


    ELEMENT.locale(ELEMENT.lang.ja)
    var vm = new Vue({
        el: '#app',
        data: {
            newItem: '',
            todos: [],
            show: false,
            radio: 'p'
        },
        watch: {
            todos: {
                handler: function() {
                    localStorage.setItem('todos', JSON.stringify(this.todos))
                },
                deep: true
            }
        },
        mounted: function() {
            this.todos = JSON.parse(localStorage.getItem('todos')) || []
        },
        methods: {
            addItem: function() {
                var item = {
                    title: this.newItem,
                    isDone: false,
                    picked: 'p'
                }
                this.todos.push(item)
                this.newItem = ''
            },
            toggle: function() {
                this.show = !this.show
            },
            deleteItem: function(index){
                if(confirm('are you sure?')) {
                    this.todos.splice(index, 1)
                }
            },
            purge: function(index){
                if(!confirm('delete finished?')) {
                    return
                }
                this.todos = this.remaining
            }
        },
        computed: {
            remaining: function() {
                return this.todos.filter(function(todo){
                    return !todo.isDone
                })
            }
        }
    })

})();
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

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

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

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

 追記#2018.08.20

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>議事録帳</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>

<body>
    <div id="app">
        <header class="l-header">
            <div class="l-container">
                <h1>議事録帳
                    <span class="info">({{remaining.length / todos.length}})</span>
                </h1>
            </div>
        </header>
        <div class="l-container">
            <ul v-if="todos.length">
                <li v-for="(todo, index) in todos">
                    <input type="checkbox" v-model="todo.isDone">
                    <span class="textView" v-bind:class="todo.picked" v-bind:class="{done: todo.isDone}">{{ todo.title }}</span>
                    <div class="el-button-group">
                        <button type="button" class="el-button el-button--primary"><i class="el-icon-edit" v-on:click="toggle(index)"></i></button>
                        <button type="button" class="el-button el-button--primary"><i class="el-icon-delete" v-on:click="deleteItem"></i></button>
                    </div>
                    <div v-show="show[index]">
                        <input type="radio" id="p" value="p" v-model="todo.picked">
                        <label for="p">p</label>
                        <input type="radio" id="h1" value="h1" v-model="todo.picked">
                        <label for="h1">h1</label>
                        <input type="radio" id="h2" value="h2" v-model="todo.picked">
                        <label for="h2">h2</label>
                    </div>
                </li>
            </ul>
            <ul v-else>
                <li>Nothing to do</li>
            </ul>
            <form v-on:submit.prevent="addItem">
                <div class="bottomArea">
                    <el-row>
                        <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>
                        <el-col :span="19">
                            <el-input v-model="newItem" placeholder="Please text" v-model="input"></el-input>
                        </el-col>
                        <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>
                    </el-row>
                </div>
            </form>
            <pre>{{show}}</pre>
            <pre>{{todos}}</pre>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="http://unpkg.com/element-ui/lib/umd/locale/ja.js"></script>
    <script src="js/common.js"></script>
</body>

</html>
(function () {
    //'use strict';


    ELEMENT.locale(ELEMENT.lang.ja)
    var vm = new Vue({
        el: '#app',
        data: {
            newItem: '',
            todos: [],
            show: [],
            radio: 'p'
        },
        watch: {
            todos: {
                handler: function () {
                    localStorage.setItem('todos', JSON.stringify(this.todos))
                },
                deep: true
            }
        },
        mounted: function () {
            this.todos = JSON.parse(localStorage.getItem('todos')) || []
        },
        methods: {
            addItem: function () {
                var item = {
                    title: this.newItem,
                    isDone: false,
                    picked: 'p'
                }
                this.todos.push(item)
                this.show.push(false)
                this.newItem = ''
            },
            toggle: function (index) {
                this.show.splice(index, 1, !this.show[index])
            },
            deleteItem: function (index) {
                if (confirm('are you sure?')) {
                    this.todos.splice(index, 1)
                }
            },
            purge: function (index) {
                if (!confirm('delete finished?')) {
                    return
                }
                this.todos = this.remaining
            }
        },
        computed: {
            remaining: function () {
                return this.todos.filter(function (todo) {
                    return !todo.isDone
                })
            }
        }
    })

})();

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/17 23: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のみとなっておりました。

    勉強不足で申し訳ございません、

    キャンセル

  • 2018/08/20 10:03

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

    キャンセル

  • 2018/08/20 10:56

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

    キャンセル

+1

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

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

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

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

<i class="el-icon-edit" v-on:click="toggle(index)">
methods: {
  toggle: function(index) {
    this.show[index] = !this.show[index];
  },
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/17 16:03 編集

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

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    18136questions

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

  • Vue.js

    934questions

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