Including a standalone component in vue ant design steps - vue.js

I want to use any design steps component and i wonder how i can include a standalone component from https://www.antdv.com/components/steps/
<template>
<div>
<a-steps :current="current">
<a-step v-for="item in steps" :key="item.title" :title="item.title" />
</a-steps>
<div class="steps-content">
{{ steps[current].content }}
</div>
<div class="steps-action">
<a-button v-if="current < steps.length - 1" type="primary" #click="next">
Next
</a-button>
<a-button
v-if="current == steps.length - 1"
type="primary"
#click="$message.success('Processing complete!')"
>
Done
</a-button>
<a-button v-if="current > 0" style="margin-left: 8px" #click="prev">
Previous
</a-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
current: 0,
steps: [
{
title: 'First',
content: 'First-content',
},
{
title: 'Second',
content: 'Second-content',
},
{
title: 'Last',
content: 'Last-content',
},
],
};
},
methods: {
next() {
this.current++;
},
prev() {
this.current--;
},
},
};
</script>
<style scoped>
.steps-content {
margin-top: 16px;
border: 1px dashed #e9e9e9;
border-radius: 6px;
background-color: #fafafa;
min-height: 200px;
text-align: center;
padding-top: 80px;
}
.steps-action {
margin-top: 24px;
}
</style>
this is the code that assigns content in steps
steps: [
{
title: 'First',
content: 'First-content',
},
{
title: 'Second',
content: 'Second-content',
},
{
title: 'Last',
content: 'Last-content',
},
],
How can i include a standalone component.vue here
content: 'First-content',

Change content from a string to a component definition:
import FirstContent from '#/components/FirstContent.vue'
import SecondContent from '#/components/SecondContent.vue'
import LastContent from '#/components/LastContent.vue'
export default {
data() {
return {
steps: [
{
title: 'First',
content: FirstContent,
},
{
title: 'Second',
content: SecondContent,
},
{
title: 'Last',
content: LastContent,
},
],
}
},
}
In your template, replace the string interpolation with <component>:
<component :is="steps[current].content" />
demo

Related

VueDraggable multiDrag and selected-class props not work in Nuxt.js

I currently use vue-draggable to make drag and drop component in my latest Nuxt project.
My package.json is like that (with the latest version of vuedraggable)
"nuxt": "^2.14.12",
"vuedraggable": "^2.24.3",
// I also use those plugins
"#nuxtjs/vuetify": "^1.11.3",
First of all, I tried to make mini-sample referred to this sample.
And I made code like below
I just changed :list to v-model in draggable tag, and use nuxt-property-decorator instead of export default. referred to latest vue-draggable
<template>
<div id="app">
<div class="flex">
<div class="flex-1">
Target Category Items: {{ targetCategoryItems.length }}
<div class="draggable-container">
<draggable
v-model="targetCategoryItems"
draggable=".element"
group="elements"
:multi-drag="true"
class="draggable"
selected-class="selected-item"
>
<div
v-for="element in targetCategoryItems"
:key="element.ItemID"
class="draggable-element"
>
<div class="item-text">
<div>[{{ element.ItemID }}]</div>
<div>{{ element.ItemName }}</div>
</div>
</div>
</draggable>
</div>
</div>
<div class="flex-1">
Source Category Items: {{ sourceCategoryItems.length }}
<div class="draggable-container">
<draggable
v-model="sourceCategoryItems"
draggable=".element"
group="elements"
:multi-drag="true"
class="draggable"
selected-class="selected-item"
#select="selectItems"
>
<div
v-for="element in sourceCategoryItems"
:key="element.ItemID"
class="draggable-element"
>
<div class="item-text">
<div>[{{ element.ItemID }}]</div>
<div>{{ element.ItemName }}</div>
</div>
</div>
</draggable>
</div>
</div>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
export default {
components: { draggable },
data() {
return {
sourceCategoryItems: [
{ ItemID: "566GR", ItemName: "Leaf Urn", PhotoName: "" },
{ ItemID: "575GD", ItemName: "Italian Villa Planter", PhotoName: "" },
{ ItemID: "576GR", ItemName: "Palm Topiary Planter", PhotoName: "" },
],
targetCategoryItems: [
{ ItemID: "F238", ItemName: "Cuadrado Side Table", PhotoName: "" },
{ ItemID: "F239", ItemName: "Triangulo Side Table", PhotoName: "" },
{ ItemID: "F285", ItemName: "Kew Occassional Table", PhotoName: "" },
{ ItemID: "F286", ItemName: "Tuileries Coffee Table", PhotoName: "" },
{ ItemID: "F296", ItemName: "Heligan Table", PhotoName: "" },
],
};
},
methods: {
toggle(todo) {
todo.done = !todo.done;
},
selectItems(event) {
console.log(event.items);
},
},
};
</script>
<style scoped>
.flex {
display: flex;
}
.flex-1 {
flex: 1;
}
.draggable-container {
border: 1px solid black;
padding: 10px;
margin: 10px;
}
.draggable-element {
padding: 10px;
margin: 10px;
background-color: lightgrey;
}
.selected-item {
background-color: red;
opacity: 0.5;
}
</style>
The result is like that
It seems that there is no problem, but I clicked the left side table, background-color never changed and I couldn't drag and drop any items.
I also checked the same issues, "SortableJS / Vue.Draggable multi-drag option not working" and "Use with Nuxt? #525". So I tried to make drag.js in src/plugins, but it doesn't work either.
So, how can I correctly use muli-drag and selected-class props in Nuxt?
This is issues Github repository.

Opening a modal from each row in table of Bootstrap-Vue

I'm using Vue2 and Bootstrap-Vue. I have a table with data (I use b-table). I want to have "edit" option on each row in order to edit the table. This option (which is an icon of gear) will open a modal and display a view boxes. In my view I have:
<template>
<div>
<b-table class="text-center" striped hover
:items="items"
:bordered=tableBordered
:fields=tableFields
:label-sort-asc=tableLabelSortAsc>
<template #cell(view)="data">
<a target="_blank" rel="noopener" class="no-link" :href="data.item.url">
<b-icon icon="eye-fill"/>
</a>
</template>
<template #cell(edit)="data">
<b-icon icon="gear-fill"/>
<edit-info-modal :data="data"/>
</template>
</b-table>
</div>
</template>
<script>
import EditInfoModal from './EditInfoModal.vue';
import { BIcon } from 'bootstrap-vue';
export default {
components: {
'b-icon': BIcon,
'edit-info-modal': EditInfoModal
},
data() {
return {
tableBordered: true,
tableLabelSortAsc: "",
tableFields: [
{ sortable: false, key: 'edit', label: 'edit' },
{ sortable: true, key: 'comments', label: 'comments' },
{ sortable: false, key: 'view', label: 'view' }
],
items: [
{
"comments": "test",
"url": "some_url"
}
]
}
}
}
</script>
<style scoped>
div {
margin: auto 0;
width: 100%;
}
a.no-link {
color: black;
text-decoration: none;
}
a:hover.no-link {
color: black;
text-decoration: none;
cursor: pointer;
}
</style>
It creates a table with three columns - the view column (with eye icon) which redirects to the url, the comments column and the edit column (with gear icon) which should open the modal.
Now, I'm trying to have the modal in a separated Vue file called EditInfoModal:
<template>
<div>
<b-modal id="modal-1" title="BootstrapVue">
<p class="my-4">Hello from modal!</p>
</b-modal>
</div>
</template>
<script>
import { BModal } from 'bootstrap-vue';
export default {
props: {
data: Object
},
components: {
'b-modal': BModal
}
}
</script>
<style scoped>
div {
margin: auto 0;
width: 100%;
}
</style>
First of all, it does not open the modal. Reading over the internet I noticed that I should add isModalOpen field and update it each time and then create the watch method. But here I have a modal for each row. What is the recommended way to keep track of the opened modal (only one is opened at any given time)?
Step 1: install BootstrapVue package and references in main.js
import { BootstrapVue, BootstrapVueIcons } from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
Vue.use(BootstrapVue);
Vue.use(BootstrapVueIcons);
Step 2: App.vue component
<template>
<div id="app">
<b-table
class="text-center"
striped
hover
:items="items"
:bordered="tableBordered"
:fields="tableFields"
:label-sort-asc="tableLabelSortAsc">
<template #cell(view)="data">
<a target="_blank" rel="noopener" class="no-link" :href="data.item.url">
<b-icon icon="eye-fill" />
</a>
</template>
<template #cell(edit)="data">
<b-icon icon="gear-fill" #click.prevent="editTable(data)" />
</template>
</b-table>
<edit-info-modal :data="data" :showModal="showModal" />
</div>
</template>
<script>
import { BIcon, BTable } from "bootstrap-vue";
import EditInfoModal from "./components/EditInfoModal.vue";
export default {
name: "App",
components: {
"b-table": BTable,
"b-icon": BIcon,
"edit-info-modal": EditInfoModal,
},
data() {
return {
tableBordered: true,
tableLabelSortAsc: "",
tableFields: [
{ sortable: false, key: "edit", label: "edit" },
{ sortable: true, key: "comments", label: "comments" },
{ sortable: false, key: "view", label: "view" },
],
items: [
{
comments: "Vue CRUD Bootstrap app",
url: "https://jebasuthan.github.io/vue_crud_bootstrap/",
},
{
comments: "Google",
url: "https://www.google.com/",
},
],
data: "",
showModal: false,
};
},
methods: {
editTable(data) {
this.data = Object.assign({}, data.item);;
this.showModal = true;
// this.$root.$emit("edit-table", Object.assign({}, data));
// this.$bvModal.show("modal-1");
},
},
};
</script>
<style scoped>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
div {
margin: auto 0;
width: 100%;
}
a.no-link {
color: black;
text-decoration: none;
}
a:hover.no-link {
color: black;
text-decoration: none;
cursor: pointer;
}
</style>
Step 3: Child component EditInfoModal.vue
<template>
<div>
<b-modal v-model="showModal" id="modal-1" title="Edit Table">
<p class="my-4">Hello from modal!</p>
<p>Comments: {{ data.comments }}</p>
<p>
URL: <a :href="data.url">{{ data.url }}</a>
</p>
</b-modal>
</div>
</template>
<script>
import { BModal } from "bootstrap-vue";
export default {
// data() {
// return {
// data: "",
// showModal: "",
// };
// },
props: ["data", "showModal"],
components: {
"b-modal": BModal,
},
// mounted() {
// this.$root.$on("edit-table", (data) => {
// this.data = data.item;
// });
// },
};
</script>
<style scoped>
div {
margin: auto 0;
width: 100%;
}
</style>
DEMO Link

Component not rendering nor providing an error

I have a table in a component, which I render into another component however, when I render the component inside of another component, it is not appearing, and due to the complete lack of errors I can't even proceed. I've checked how I've imported etc and it seems correct. But perhaps someone can spot something I haven't. I'm very new to VueJs so apologies for the untrimmed code, I'm not 100% on what could be relevant yet.
File I'm Importing Into.vue
<template>
<div>
<b-table
:striped="striped"
:bordered="false"
:data="participants"
detailed
class="participant-table"
:row-class="() => 'participant-row'"
>
<InternalTable></InternalTable>
<b-table-column field="columnValue" v-slot="props2" class="attr-column">
<b-table
:bordered="false"
class="attr-table"
:striped="true"
:data="props2.row.columnValues"
>
<b-table-column field="columnName" v-slot="itemProps">
<SelectableAttribute
:attr-name="props2.row.fieldClass"
:attr-id="itemProps.row.id"
:model-id="itemProps.row.id"
model-name="NewParticipant"
>
{{ itemProps.row.value }}
</SelectableAttribute>
</b-table-column>
</b-table>
</b-table-column>
</b-table>
</div>
</template>
<script>
import { snakeCase } from "snake-case";
import InternalTable from './InternalTable'
import SelectableAttribute from '../groups/SelectableAttribute'
export default {
props: {
bordered: true,
striped: true,
participants: [
{
primaryAlias: '',
primaryEmail: '',
primaryAddress: '',
primaryPhone: '',
}
]
},
},
components: {
SelectableAttribute,
InternalTable
},
methods: {
tableDataToDataValueCells(participant) {
const fields = [
{ fieldName: 'companyNames', fieldClass: 'CompanyName' },
{ fieldName: 'aliases', fieldClass: 'Alias' },
{ fieldName: 'addresses', fieldClass: 'Address' },
{ fieldName: 'phones', fieldClass: 'Phone' },
{ fieldName: 'emails', fieldClass: 'Email' },
{ fieldName: 'birthdates', fieldClass: 'Birthdate' },
{ fieldName: 'customerNumbers', fieldClass: 'CustomerNumber' },
{ fieldName: 'ibans', fieldClass: 'BankAccount' },
];
let result = [];
fields.forEach(field => {
if (participant[field.fieldName].length > 0) {
result.push({
attributeName: field.fieldName,
columnName: I18n.t(`ccenter.participant.table.${snakeCase(field.fieldName)}`),
columnValues: participant[field.fieldName],
fieldClass: field.fieldClass,
})
}
});
return result;
}
}
}
</script>
<style>
.table tbody tr.detail:last-child td {
border-width: 1px !important;
}
.participant-table .participant-row td {
word-break: break-word;
font-size: 13px;
padding: 10px 5px;
}
.cell-action {
padding-left: 0px !important;
padding-right: 0px !important;
}
.cell-action .b-radio {
margin: 0px;
}
.attr-table table thead {
display: none;
}
.attr-table table td {
border: none;
}
.attrs-detail-container table tr td:nth-child(2) {
padding: 0 !important;
}
.attrs-detail-container table thead {
display: none;
}
</style>
InternalTable.Vue
<template>
<b-table :data="participants" detailed class="participant-table" :row-class="() => 'participant-row'">
<b-table-column field="primaryAlias" :label="t('participant.table.primary_alias')" v-slot="props">
<template v-if="props.row.primaryAlias">{{ props.row.primaryAlias.value }}</template>
<template v-else>-</template>
</b-table-column>
<b-table-column field="primaryEmail" :label="t('participant.table.primary_email')" v-slot="props">
<template v-if="props.row.primaryEmail">{{ props.row.primaryEmail.value }}</template>
<template v-else>-</template>
</b-table-column>
<b-table-column field="primaryAddress" :label="t('participant.table.primary_address')" v-slot="props">
<template v-if="props.row.primaryAddress">{{ props.row.primaryAddress.value }}</template>
<template v-else>-</template>
</b-table-column>
<b-table-column field="primaryPhone" :label="t('participant.table.primary_phone')" v-slot="props">
<template v-if="props.row.primaryPhone">{{ props.row.primaryPhone.value }}</template>
<template v-else>-</template>
</b-table-column>
<b-table-column v-slot="props" cell-class="cell-action">
<slot v-bind="props.row">
</slot>
</b-table-column>
<template slot="detail" slot-scope="props">
<b-table class="attrs-detail-container" :data="tableDataToDataValueCells(props.row)" cell-class="with-bottom-border">
<b-table-column field="columnName" v-slot="props">
<b>{{ props.row.columnName }}</b>
</b-table-column>
</b-table>
</template>
</b-table>
</template>
<script>
import { snakeCase } from "snake-case"
export default {
props: {
participants: {
type: Array,
}
},
methods: {
tableDataToDataValueCells(participant) {
const fields = [
{ fieldName: 'companyNames', fieldClass: 'CompanyName' },
{ fieldName: 'aliases', fieldClass: 'Alias' },
{ fieldName: 'addresses', fieldClass: 'Address' },
{ fieldName: 'phones', fieldClass: 'Phone' },
{ fieldName: 'emails', fieldClass: 'Email' },
{ fieldName: 'birthdates', fieldClass: 'Birthdate' },
{ fieldName: 'customerNumbers', fieldClass: 'CustomerNumber' },
{ fieldName: 'ibans', fieldClass: 'BankAccount' },
];
let result = [];
fields.forEach(field => {
if (participant[field.fieldName].length > 0) {
result.push({
attributeName: field.fieldName,
columnName: I18n.t(`ccenter.participant.table.${snakeCase(field.fieldName)}`),
columnValues: participant[field.fieldName],
fieldClass: field.fieldClass,
})
}
});
return result;
}
}
};
</script>
<style scoped>
.table tbody tr.detail:last-child td {
border-width: 1px !important;
}
.participant-table .participant-row td {
word-break: break-word;
font-size: 13px;
padding: 10px 5px;
}
.cell-action {
padding-left: 0px !important;
padding-right: 0px !important;
}
.cell-action .b-radio {
margin: 0px;
}
.attr-table table thead {
display: none;
}
.attr-table table td {
border: none;
}
.attrs-detail-container table tr td:nth-child(2) {
padding: 0 !important;
}
.attrs-detail-container table thead {
display: none;
}
</style>
What I see is that you trying to use props in your InternalTable.vue, which you used like this:
props: {
participants: {
type: Array,
}
}
In your Into.vue, you just call your component without providing these props. You should change:
<InternalTable></InternalTable>
to
<InternalTable :participants="participants"></InternalTable>
Looks like your b-table isn´t rendering because you didn´t provide data.
EDIT: Your data needs to be filled first
Currently, your array participants is empty, it just consists of:
participants: {
type: Array,
default: null,
}
In your InternalTable.vue you refer to primaryAlias, primaryEmail, primaryAddress and primaryPhone at your b-table-column´s. This data isn´t provided yet, thats why the table renders without data. You need to provide an array with a minimum structure of:
participants: [
{
primaryAlias: '',
primaryEmail: '',
primaryAddress: '',
primaryPhone: ''
}
]

nuxtjs add and remove class on click on elements

I am new in vue and nuxt and here is my code I need to update
<template>
<div class="dashContent">
<div class="dashContent_item dashContent_item--active">
<p class="dashContent_text">123</p>
</div>
<div class="dashContent_item">
<p class="dashContent_text">456</p>
</div>
<div class="dashContent_item">
<p class="dashContent_text">789</p>
</div>
</div>
</template>
<style lang="scss">
.dashContent {
&_item {
display: flex;
align-items: center;
}
&_text {
color: #8e8f93;
font-size: 14px;
}
}
.dashContent_item--active {
.dashContent_text{
color:#fff;
font-size: 14px;
}
}
</style>
I tried something like this:
<div #click="onClick">
methods: {
onClick () {
document.body.classList.toggle('dashContent_item--active');
},
},
but it changed all elements and I need style change only on element I clicked and remove when click on another
also this code add active class to body not to element I clicked
This is how to get a togglable list of fruits, with a specific class tied to each one of them.
<template>
<section>
<div v-for="(fruit, index) in fruits" :key="fruit.id" #click="toggleEat(index)">
<span :class="{ 'was-eaten': fruit.eaten }">{{ fruit.name }}</span>
</div>
</section>
</template>
<script>
export default {
name: 'ToggleFruits',
data() {
return {
fruits: [
{ id: 1, name: 'banana', eaten: false },
{ id: 2, name: 'apple', eaten: true },
{ id: 3, name: 'watermelon', eaten: false },
],
}
},
methods: {
toggleEat(clickedFruitIndex) {
this.fruits = this.fruits.map((fruit) => ({
...fruit,
eaten: false,
}))
return this.$set(this.fruits, clickedFruitIndex, {
...this.fruits[clickedFruitIndex],
eaten: true,
})
},
},
}
</script>
<style scoped>
.was-eaten {
color: hsl(24, 81.7%, 49.2%);
}
</style>
In Vue2, we need to use this.$set otherwise, the changed element in a specific position of the array will not be detected. More info available in the official documentation.

Unable to display data from vue instance in a component that is inside another componnt

I have a Vue instance that has data that I am trying to access from a component that is inside another component to iterate through all values with v-for from the items inside data, in this case either banners or posts.
I have reviewed the composing components section on the vue.js website, using their posts data as an example but am unable to utilize the posts data inside my blog-post component.
I have tried adding props to the blog-post component, to the nav-home component and have tried modifying the data in my vue app instance to return all values of data and tried to add the following to the mounted property, this.$emit('posts', this.posts) without success.
Console.log(this.posts) of course returns the data, however it isn't accessible in the nested components either product-banner or blog-post when included in the nav-home component.
Vue.component('nav-home', {
props: ['posts','banners'],
template: `<div>
<h1> Home component </h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<!-- banner -->
<product-banner
v-for="banner in banners"
v-bind:key="banner.id"
v-bind:banner="banner">
</product-banner>
<!-- post -->
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post">
</blog-post>
</div>`
})
Vue.component('blog-post', {
props: ['posts'],
template: `<h3>{{posts.title}}</h3>`
})
Vue.component('product-banner', {
props: ['banner'],
template: `<div id="product-banner">
<div class="product-container">
<h2>{{banner.title}}</h2>
<p>{{banner.content}}</p>
</div>
</div>`
})
Vue.directive('focus', {
inserted: function(el) {
el.focus();
}
})
new Vue({
el: '#app',
data: {
currentNav: 'Home',
navs: ['Home'],
posts: [
{ id: 1, title: 'Title one' },
{ id: 2, title: 'Title two' },
{ id: 3, title: 'Title three' }
],
banners: [
{id: 1, title: 'Title 1', content: 'Content 1'},
{id: 2, title: 'Title 2', content: 'Content 2'},
{id: 3, title: 'Title 3', content: 'Content 3'}
]
},
computed: {
contentComponent: function() {
return 'nav-' + this.currentNav.toLowerCase()
}
},
directive: {
focus: {
inserted: function(el) {
el.focus()
}
}
}
})
#charset "utf-8";
body {
font-family: tahoma;
color:#282828;
margin: 0px;
overflow: hidden;
}
.nav {
display: flex;
width: 100%;
height: 50%;
justify-content: center;
}
.nav > nav {
padding: 20px;
align-self: center;
border: 1px solid #000000;
margin: 0 10px 0 0;
transition: background 0.2s ease-in-out;
}
.nav > nav:hover {
cursor: pointer;
background: #cecece;
}
nav.active-nav.active, .active {
background: #cecece;
}
.contentDetails {
margin: 40px;
height: 100%;
display: block;
position: absolute;
}
/* SLIDE IN OUT */
.slide-enter {
transform: translate(100%, 0%);
opacity: 1;
}
.slide-leave-to {
transform: translate(-100%, -0%);
opacity: 0;
}
.slide-leave-active,
.slide-enter-active {
position: absolute;
transition: transform 1s ease-in-out,
opacity 0.2s ease-in-out;
}
/* FLIP IT */
.flipit-enter,
.flipit-leave-to {
opacity: 0;
transform: rotateY(50deg);
}
.flipit-enter-to,
.flipit-leave {
opacity: 1;
transform: rotateY(0deg);
}
.flipit-enter-active,
.flipit-leave-active {
transition: opacity, transform 200ms ease-out;
}
/* SLIDE UP */
.slideup-enter,
.slideup-leave-to {
opacity: 0;
position: absolute;
right: -9999px
}
.slideup-enter-to,
.slideup-leave {
opacity: 1;
right: 0;
}
.slideup-enter-active,
.slideup-leave-active {
transition: right, transform 200ms ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<!-- NAVIGATION -->
<div class="nav">
<nav v-for="nav in navs"
v-bind:key="nav"
v-bind:class="['nav-button', { active: currentNav === nav }]"
v-on:click="currentNav = nav">
{{ nav }}
</nav>
</div>
<!-- CONTENT COMPONENT-->
<transition name="flipit">
<component
v-bind:is="contentComponent"
class="contentDetails">
</component>
</transition>
</div>
I am expecting to see either the product banner or blog-post displayed from the product-banner or blog-post component inside the nav-home component.
You need to pass banners and posts as props to your nav-home component too.
<component
:is="contentComponent"
class="contentDetails"
:banners="banners"
:posts="posts"
>
Vue.component('nav-home', {
props: ['banners', 'posts'],
template: `
<div>
<h1> Home component </h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<!-- banner -->
<product-banner
v-for="banner in banners"
:key="'banner' + banner.id"
:banner="banner"
/>
<!-- post -->
<blog-post
v-for="post in posts"
:key="'post' + post.id"
:post="post"
/>
</div>
`
})
Vue.component('blog-post', {
props: ['post'],
template: `<h3>{{post.title}}</h3>`
})
Vue.component('product-banner', {
props: ['banner'],
template: `
<div id="product-banner">
<div class="product-container">
<h2>{{banner.title}}</h2>
<p>{{banner.content}}</p>
</div>
</div>
`
})
new Vue({
el: '#app',
data: {
currentNav: 'Home',
navs: ['Home'],
posts: [
{
id: 1,
title: 'Title one'
},
{
id: 2,
title: 'Title two'
},
{
id: 3,
title: 'Title three'
}
],
banners: [
{
id: 1,
title: 'Title 1',
content: 'Content 1'
},
{
id: 2,
title: 'Title 2',
content: 'Content 2'
},
{
id: 3,
title: 'Title 3',
content: 'Content 3'
}
]
},
computed: {
contentComponent: function() {
return 'nav-' + this.currentNav.toLowerCase()
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<!-- NAVIGATION -->
<div class="nav">
<nav
v-for="nav in navs"
:key="nav"
:class="['nav-button', { active: currentNav === nav }]"
#click="currentNav = nav"
>
{{ nav }}
</nav>
</div>
<!-- CONTENT COMPONENT-->
<transition name="flipit">
<component
:is="contentComponent"
class="contentDetails"
:banners="banners"
:posts="posts"
>
</component>
</transition>
</div>
I've made a few others tweaks too:
Shortening v-bind: to : and v-on: to #.
Changing the key attributes so that banners and posts wouldn't clash with each other.
Renaming the prop for blog-post from posts to post, updating the template accordingly.