ラック
Home > ブログ > 記事 > 2018年12月 > フラグをリアクティブにして2YY/vue-accordionをv-forで展開された要素に適応する

フラグをリアクティブにして2YY/vue-accordionをv-forで展開された要素に適応する

カテゴリ: プログラム

2YY/vue-accordionを使ってアコーディオンメニューを作りたいと考えました。また、アコーディオンの中身はdataで可変にしたい、と。

最初はv-forで完全に同じ内容でループさせていたので、アコーディオンの開閉を1つのフラグで見ていて、1つでも開くと全て開く、という動作になってしまいました。当たり前といえば当たり前ですね。

そこで、下記のようにしました。Vue初心者なのと突貫で作ったのでコードが粗いですが。

<div class="accordion" id="sidebar">
    <div class="ui list">
        <div class="item" v-for="content in accordionMenu" :key="content.id" ref="item"><!-- 最初のv-for -->
            <div class="content">
                <div class="header" @click="toggleIsOpen(content.id)"></div><!-- toggleIsOpenメソッドにIDを引数として渡す -->
                <accordion :duration="accordion.duration" :is-open="accordion[`isOpen${content.id}`]"><!-- 2yy-vue-accordion -->
                    <div class="list" v-for="list in content.contents" :key="list.id"><!-- v-forの入れ子 -->
                        <div class="item">
                            <div class="content">
                                <div class="header"></div>
                            </div>
                        </div>
                    </div>
                </accordion>
            </div>
        </div>
    </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.19/vue.js"></script>
<script src="https://cdn.rawgit.com/2YY/vue-accordion/78d13679/dist/vue-accordion.min.js"></script>
<script>
new Vue({
    el: '#sidebar',
    data: {
        accordion: {
            duration: ".3s"
        },
        accordionMenu: [
            {
                id: 0,
                title: "test",
                contents: [
                    {
                        id: 0,
                        title: "test_1"
                    }
                ]
            },
            {
                id: 1,
                title: "test2",
                contents: [
                    {
                        id: 0,
                        title: "test2_1"
                    },
                    {
                        id: 1,
                        title: "test2_2"
                    },
                    {
                        id: 2,
                        title: "test2_3"
                    }
                ]
            },
            {
                id: 2,
                title: "test3",
                contents: [
                ]
            }
        ]
    },
    mounted() {
        const accordionItem = this.$refs.item
        for(let i = 0; i < accordionItem.length; i++) {
            this.accordion[`isOpen${i}`] = false //data.accordion.isOpenX(Xは数字)にfalseをセット
        }
    },
    methods: {
        toggleIsOpen(num) {
            this.accordion[`isOpen${num}`] = !this.accordion[`isOpen${num}`]
        }
    }
})
</script>

しかし、今度は反応がありません。methodsの中でconsole.logで拾ってみると、確かにフラグはtrue/falseで切り替わっているのですが……うーん。

<div class="header" @click="toggleIsOpen(content.id)"></div><!-- toggleIsOpenメソッドにIDを引数として渡す -->

としてdata.accordionの中身を見てみると……

{ duration: ".3s" }

……あれ?isOpen0: falseとか入ってくると思ったのですが、ありません。

ここまで来てようやく、「リアクティブになってないのでは?」と思い至りました。そこで、下記のように変更。

<div class="accordion" id="sidebar">
    <div class="ui list">
        <div class="item" v-for="content in accordionMenu" :key="content.id" ref="item"><!-- 最初のv-for -->
            <div class="content">
                <div class="header" @click="toggleIsOpen(content.id)"></div><!-- toggleIsOpenメソッドにIDを引数として渡す -->
                <accordion :duration="accordion.duration" :is-open="accordion[`isOpen${content.id}`]"><!-- 2yy-vue-accordion -->
                    <div class="list" v-for="list in content.contents" :key="list.id"><!-- v-forの入れ子 -->
                        <div class="item">
                            <div class="content">
                                <div class="header"></div>
                            </div>
                        </div>
                    </div>
                </accordion>
            </div>
        </div>
    </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.19/vue.js"></script>
<script src="https://cdn.rawgit.com/2YY/vue-accordion/78d13679/dist/vue-accordion.min.js"></script>
<script>
new Vue({
    el: '#sidebar',
    data: {
        accordion: {
            duration: ".3s"
        },
        accordionMenu: [
            {
                id: 0,
                title: "test",
                contents: [
                    {
                        id: 0,
                        title: "test_1"
                    }
                ]
            },
            {
                id: 1,
                title: "test2",
                contents: [
                    {
                        id: 0,
                        title: "test2_1"
                    },
                    {
                        id: 1,
                        title: "test2_2"
                    },
                    {
                        id: 2,
                        title: "test2_3"
                    }
                ]
            },
            {
                id: 2,
                title: "test3",
                contents: [
                ]
            }
        ]
    },
    mounted() {
        const accordionItem = this.$refs.item
        for(let i = 0; i < accordionItem.length; i++) {
            this.$set(this.accordion, `isOpen${i}`, false) //セット方法を変更
        }
    },
    methods: {
        toggleIsOpen(num) {
            this.accordion[`isOpen${num}`] = !this.accordion[`isOpen${num}`]
        }
    }
})
</script>

これで動くようになりました。あー、これが初心者がよく躓くリアクティブ云々のところかぁ……と改めて感じた次第です。

参考

直接使わなかったが、今後参考になりそうな記事

{[myKey]: myValue};[]でくくってあげれば、変数名をキーに使うことができるのですね。使えそう。

タグ: javascript,Vue.js

 



関連する記事一覧