Is it possible to create semantically nested elements with Vue.js?
Example: let's say I'm building an 'accordion' element. Accordions are made up of a 'heading' and a 'content' section. The content can be toggled in and out of view by clicking the header. The final html for an element like this would be something like this:
<div class="accordion">
<div class="heading">
My Accordion
</div>
<div class="content">
Accordions are fun! Loren ipsum dolor sit amet.
This can be extensive text, include pictures, etc.
</div>
</div>
I would like to be able to create such elements in my html using syntax like this:
<accordion>
<heading>My Accordion</heading>
<content>
Accordions are fun! Loren ipsum dolor sit amet.
This can be extensive text, include pictures, etc.
</content>
</accordion>
The 'heading' and 'content' elements are not generic, and should only exist within the context of the parent 'accordion' element, so I believe they should be declared within the parent component's definition.
I know that in order to capture the innerHTML content of an element, we must use a <slot>
element, so I tried using the following templates:
<template id="heading">
<div class="heading">
<slot></slot>
</div>
</template>
<template id="content">
<div class="content">
<slot></slot>
</div>
</template>
<template id="accordion">
<div class="accordion">
<heading></heading>
<content></content>
</div>
</template>
<div id="app">
<accordion>
<heading>My Accordion</heading>
<content>
Accordions are fun. Lorem ipsum dolor sit amet.
I could add a lot more text here, or other elements.
</content>
</accordion>
</div>
And the Vue javascript...:
Vue.component('accordion', {
template: '#accordion',
components: {
heading: {
template: '#heading'
},
content: [
template: '#content'
}
}
});
Vue({
el: '#app'
});
Unfortunately, it doesn't work. I've read the official documentation several times, and within the 'Components' section, when it talks about <slot>
elements, it seems to indicate we should be able to do it - but I can't for the life of me work out how... The docs actually mention an element with a structure like this:
<app>
<app-header></app-header>
<app-footer></app-footer>
</app>
...but it doesn't give simple, concrete examples of how to do it.
The way the information is passed from parent to child element is confusing, and I have been unable to find any tutorials online that show how to setup a nested element like this. Any guidance would be greatly appreciated.
so <heading>
and <content>
should also be Vue components?
then it should look like this:
<div id="app">
<h5>Accordion test</h5>
<accordion>
<heading slot="heading">Heading Text</heading>
<content slot="content">Content Text</content>
</accordion>
<template id="accordion">
<div class="header">
<slot name="heading"></slot>
</div>
<div class="content">
<slot name="content"></slot>
</div>
</template>
<template id="heading">
<div class="template-heading">
<slot></slot>
</div>
</template>
<template id="content">
<div class="template-content">
<slot></slot>
</div>
</template>
</div>
and the JS:
var Heading = Vue.extend({
template: '#heading'
})
var Content = Vue.extend({
template: '#content'
})
var Accordion = Vue.extend({
template: '#accordion',
components: {
heading: Heading,
content: Content
}
})
Vue.component('heading', Heading)
Vue.component('content', Content)
Vue.component('accordion', Accordion)
var App = new Vue({
el: '#app',
data() {
return {
test: 'Test'
}
}
})
So:
<heading>
element goes into the slot inside of <heading>
's template. <heading>
goes into the <slot name="heading">
inside the template of <accordion>
Working fiddle: https://jsfiddle.net/Linusborg/ud9a614o/
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.