0

home.vue

<template>
  <app-navbar>
    <logo title="navbar"></logo>
    <div class="navbar-collapse">
      <link href="#first" title="first link"></link>
      <link href="#second" title="second link"></link>
      <link href="#third" title="third link"></link>
    </div>
  </app-navbar>
</template>

<script>
export default {
  name: "Home",
    components: {
      AppNavbar: () => import('@/components/navbar.vue')
    }
}
</script>

navbar.vue

<script>
  export default {
    name: "AppNavbar",
    props: {
      title: {
        type: String,
        default: "navbarDemo"
      },
      href: {
        type: String,
        default: "#"
      }
    },
    template: `
      <div class="navbar-container">
        <component :is="logo">
          <div class="navbar-brand">{{ title }}</div>
        </component>
        <ul>
          <component :is="link">
            <li class="item">
              <a :href="href" class="link">{{ title }}</a>
            </li>
          </component
        </ul>
      </div>
    </div>
    `
  };
</script>

I WANT THIS

<div class="navbar-container">
  <div class="navbar-brand">navbar</div>
  <div class="navbar-collapse">
   <ul>
     <li class="item">
       <a href="#first" class="link">first link</a>
     </li>
     <li class="item">
       <a href="#second" class="link">second link</a>
     </li>
     <li class="item">
       <a href="#third" class="link">third link</a>
     </li>
   </ul>
  </div>  
</div>

What am I doing wrong? Is component used differently? I want to use a component and have another component in it in one file (I don't want to have 20 files here just for navbar). Then compose the structure in this way. Possible?

I'm trying a similar HTML structure as here: link

4
  • <component> is used to reference a vue component. E.g. to use the imported AppNavbar in home.vue you would use <component is="AppNavbar" /> a :is is referencing a variable (string) that contains the component name Commented May 20, 2020 at 2:13
  • So how can I create more components in that navbar? Can you give an example? Commented May 20, 2020 at 2:23
  • tbh, I'm not really understanding your question, but slots do feel like what you may be looking for. Someone else has provided an answer with that in mind Commented May 20, 2020 at 2:36
  • Yes, slot is what I needed. Commented May 20, 2020 at 2:40

1 Answer 1

2

Here is what you need:

home.vue

<app-navbar :links="links">
  <template #logo>
    <img src=""/>
  </template>
</app-navbar>

data() {
  return {
    links: [
      { href: '#first", title: 'first link' },
      { href: '#second", title: 'secondlink' },
      { href: '#third", title: 'thirdlink' },
    ]
  }
}

navbar.vue

<template>
  <div class="navbar-container">
    <div class="navbar-brand">
      <slot name="logo" />
    </div>
    <div class="navbar-collapse">
      <ul>
        <li v-for="link in links" :key="link.href">
          <a :href="link.href">{{ link.title }}</a>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    links: Array
  }
}
</script>

The logo element is passed through a slot (https://fr.vuejs.org/v2/guide/components-slots.html).

You understood <component> wrongly :p <component> do not declare a component, it's only a way to use a component when its name might change.

Instead of writing <comp1 v-if="test" /> <comp2 v-else /> you could write <component :is="test ? 'comp1" : 'comp2' />. But comp1 and comp2 components still need to be declared somewhere and imported.

Did you check https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components ?

EDIT: If you want to customize links with scoped-slots:

home.vue

<app-navbar :links="links">
  <template #logo>
    <img src=""/>
  </template>

  <template #link="{ href, title }">
    <a :href="href">{{ title }}</a>
  </template>
</app-navbar>

data() {
  return {
    links: [
      { href: '#first", title: 'first link' },
      { href: '#second", title: 'secondlink' },
      { href: '#third", title: 'thirdlink' },
    ]
  }
}

navbar.vue

<template>
  <div class="navbar-container">
    <div class="navbar-brand">
      <slot name="logo" />
    </div>
    <div class="navbar-collapse">
      <ul>
        <li v-for="link in links" :key="link.href">
          <slot name="link" :href="link.href" :title="link.title" />
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    links: Array
  }
}
</script>

So the looped links are passed through the slot so the parent is handling the rendering

Sign up to request clarification or add additional context in comments.

4 Comments

Oh yes, SLOT is what I needed. I didn't work with VUE for a long time and I couldn't remember how this was handled. Yes, I checked, but I'm not very good at English. Thanks, you helped me.
To answer your other question, you can't declare multiple components in a single .vue file. If you don't want to create a single file for a single component it means it's not a reusable component and it shouldn't exist ;) (see, my example works without any logo or link component)
Yea, is here better way without use this "template" tag? Or a similar way in the attached link?
you mean the <template #logo>? it's mandatory for named slots (not default slot). For links you could use scoped-slots if you want to customize them but you still have to pass an array of objets to the component so it can loops (looping hover nodes of a slot is not possible). I edited my answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.