背景
Reactで作る汎用的なシンプルアコーディオン をVueで実装する。
実装
SimpleAccordion.vue
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import { VNode } from 'vue'
@Component
export default class SimpleAccordion extends Vue {
@Prop({ default: false }) value!: boolean
state: boolean = false
get display() {
return this.state ? 'block' : 'none'
}
@Watch('value')
update() {
this.state = this.value
}
created() {
this.state = this.value
}
toggle() {
const changed = !this.state
changed ? this.$emit('open') : this.$emit('close')
this.state = changed
this.$emit('input', changed)
}
render(h: any) {
return h(
'div',
{},
(this.$slots.default as VNode[]).map(node => {
if (!node.componentOptions) return null
if (node.componentOptions.tag === 'SimpleAccordionSummary')
return h(
'div',
{ on: { click: this.toggle } },
node.componentOptions.children
)
if (node.componentOptions.tag === 'SimpleAccordionDetails')
return h(
'div',
{ style: { display: this.display } },
node.componentOptions.children
)
})
)
}
}
</script>
SimpleAccordionSummary.vue
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class SimpleAccordionSummary extends Vue {}
</script>
SimpleAccordionDetails.vue
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class SimpleAccordionDetails extends Vue {}
</script>
実用例
Sample.vue
<template>
<SimpleAccordion v-model="show">
<SimpleAccordionSummary>
<p>概要</p>
{/* ここをクリックすると開いたり閉じたりする */}
</SimpleAccordionSummary>
<SimpleAccordionDetails>
<p>詳細</p>
</SimpleAccordionDetails>
</SimpleAccordion>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component
export default class Sample extends Vue {
show = false
}
</script>