In this chapter we will be exploring how to go about implementing a new section component using the classic Vue single file components. We will demonstrate the process by referencing to an example project that you will see below.
You can see in the following picture that multiple components are displayed as unknown in our example project. These components have been created in First Spirit but in our pwa the UI has not been implemented yet.
By clicking on the question mark on one of the unknown components the dev info tells us all the information the component has access to. In our example we can see that there should be a component of type Section
. We can also see that the 'sectionType' property of this missing section is called teaser
.
The section components in our demo project are located in ~/components/Section/
. That’s where we are going to create a new file for the example component.
In general the ~/components
folder holds all the reusable components in your project. You are free to create subfolders as you like and come up with a custom folder structure. Remember to update any references to your components accordingly.
We name our new file Teaser.vue
and add a template tag to the file so that we can see something when we fire up the dev server:
<template>
<div>
<h1>Teaser Component</h1>
</div>
</template>
Now we need to reference our newly created teaser component inside the general Section.vue
component which can be found in the ~/components/PageBodyContent/
directory.
Add a teaser
case to the computed sectionComponent
property. Make sure to name the case after the respective sectionType
and name the component that is going to be resolved according to the path where it is located.
In this case Section/Teaser.vue
becomes SectionTeaser
. As of now, the component name needs to be a hardcoded string. Variable component resolving is not yet possible in Nuxt 3.
// ~/components/PageBodyContent/Section.vue
...
const sectionComponent = computed(() => {
switch (props.content.sectionType) {
case "teaser":
return resolveComponent("SectionTeaser");
default:
return resolveComponent("Unknown");
}
});
...
When we go back to the browser, instead of the unknown component we now see our new teaser component.
Our component is recognized correctly. But we still do not display any data from the CaaS in our component. For that we hover over our new component and click on the appearing question mark on the right side again.
This shows us all the data available to display. In our example there is a property called st_jumbo_headline
that we are going to display.
Our newly created Teaser.vue
component has access to a data
property that gets passed from the general Section component. You can provide some typesafety by adding a custom interface to this property.
To display data in our example we modify the Teaser.vue
component like this:
<template>
<div>
<h1>Teaser Component: {{ data.st_jumbo_headline }}</h1>
</div>
</template>
<script setup lang="ts">
interface Teaser {
st_jumbo_headline:string
}
defineProps<{ data: Teaser }>();
</script>
The result should look like this:
To render richtext, image or button elements you can use the RichText.vue
, Image.vue
and Button.vue
components which can be found under the ~/components/Elements/
folder. We use them like this in our example teaser component:
<template>
<div>
<h1>Teaser Component: {{ data.st_jumbo_headline }}</h1>
<ElementsRichText :richtext="data.st_headline" />
<ElementsImage :image="data.st_picture" :alt="data.st_picture_alt" />
<ElementsButton :button="data.st_button" @button-click="clickHandler" />
</div>
</template>
<script setup lang="ts">
import { Image, RichTextElement } from "fsxa-api";
interface Teaser {
st_jumbo_headline:string
st_headline: RichTextElement[];
st_picture?: Image;
st_picture_alt?: string;
st_button: MyCustomButtonInterface
}
defineProps<{ data: Teaser }>();
function clickHandler(){
// do sth.
}
</script>
Of course, you can modify all components and adjust them according to your specific requirements. In our implementation example ElementsButton
emits a buttonClick
event which can be hooked into with @button-click
. Define your click handler function inside the script tag as shown above.