動機
Vue.js大好き!ですが、毎回面倒なのがアコーディオンの実装。
他の方が作ったコンポーネントもたくさんあげられているのですが、ページ内に複数のアコーディオンを設置したい場合に、いちいちjs側をいじる必要があるものがほとんどです。(本来そうあるべき、なのかもしれませんが…)
エンジニアさんはjs、デザイナーさんはhtml側などと気軽に分担して書けるのは、Vue.jsの利点でもあるので、一度Vue.jsに読んでおけば複数のアコーディオンもhtml側の編集だけで対応できる実装をしました。
実装
js
var accordion = {
data: function () {
return {
openedAccordions: []
};
},
components: {
accordion: {
props: ['opened', 'duration', 'closedHeight'],
computed: {
innerHeight: function () {
return this.$refs.inner.clientHeight;
},
maxHeight: function () {
return this.opened ? this.innerHeight : (this.closedHeight || 0);
},
transitionDuration: function () {
return this.duration || 0.5;
},
wrapStyle: function () {
return {
maxHeight: this.maxHeight + 'px',
transitionDuration: this.transitionDuration + 's',
transitionProperty: 'max-height',
overflow: 'hidden',
};
},
},
template: '\
<div :style="wrapStyle">\
<div ref="inner">\
<slot></slot>\
</div>\
</div>',
},
},
methods: {
isOpenedAccordion: function (key) {
return this.openedAccordions.indexOf(key) !== -1;
},
openAccordion: function (key) {
if (this.isOpenedAccordion(key)) return;
return this.openedAccordions.push(key);
},
closeAccordion: function (key) {
var newOpened = [];
for (var i = 0; i < this.openedAccordions.length; i++) {
if (this.openedAccordions[i] === key) continue;
newOpened.push(this.openedAccordions[i]);
};
this.openedAccordions = newOpened;
},
toggleAccordion: function (key, open) {
open = open || !this.isOpenedAccordion(key);
return open ? this.openAccordion(key) : this.closeAccordion(key);
},
},
};
new Vue({
el: '#app',
mixins: [accordion], // mixinで読み込む
});
html
<div id="app">
<button @click="toggleAccordion('hoge')" :class="{opened: isOpenedAccordion('hoge')}">
<span v-if="isOpenedAccordion('hoge')">とじる</span>
<span v-else>ひらく</span>
</button>
<accordion :opened="isOpenedAccordion('hoge')">
じゅげむじゅげむ<br>
ごこうのすりきれ<br>
かいじゃりすいぎょのすいぎょうまつうんらいまつふうらいまつ<br>
くうねるところにすむところ<br>
やぶらこうじのぶらこうじ<br>
ぱいぽぱいぽぱいぽのしゅーりんがん<br>
しゅーりんがんのぐーりんだい<br>
ぐーりんだいのぽんぽこぴーのぽんぽこなのちょうきゅうめいのちょうすけ
<button @click="closeAccordion('hoge')">とじる</button>
</accordion>
</div>
こんな感じで書いておくと、 <accordion>
タグに囲まれた部分が、ボタンにより閉じたり開いたりできます。
ちなみに、 hoge
の部分を変えてアコーディオンを増やしていけば、複数アコーディオンにも対応できます。
プロパティ
速度
<accordion>
に duration
属性を指定すると、アコーディオンの表示の時間を10秒に設定できます。
<accordion duration="10"> // 10秒かけて開く
閉じた時の見えている領域
<accordion>
に closed-height
属性を指定すると、アコーディオンが閉じた時にも見えている領域を作ることができます。
複数の投稿を最初の1つだけ見せて、もっと見るボタンに使ったりもできそうですね。
<accordion closed-height="100"> // 100pxだけ最初から表示
やってみて
- 普段ES6でばかり書いていますが、今回は他の方がコピペしてそのままブラウザで読んでも使えるような書き方でがんばりました。ES6の構文使えないのつらたん…
- mixinなので、ファイル分けて
export
/import
してもよいかもしれません。 - Vue.jsだいすき!