2017-07-27 1 views
1

Im travaillant sur l'application Vue.js sensible avec Uikit. Je dois créer 2 menus - un pour la version de bureau, un pour le mobile. Donc, je dois définir les mêmes éléments de menu 2 fois, d'abord pour la fente de liens de bureau, la deuxième fois pour le mobile. Je ne veux pas le définir 2x. Comment puis-je traiter ce problème avec élégance? Des idées?Vue - un moyen de réutiliser SLOT?

<template id="app"> 
    <app-layout> 

    <template slot="navlinks-desktop"> 
     <router-link to="/link1" tag="li" exact><a>Link 1</a></router-link> 
     <router-link to="/link2" tag="li" exact><a>Link 2</a></router-link> 
    </template> 

    <template slot="navlinks-mobile"> 
     <router-link to="/link1" tag="li" exact><a>Link 1</a></router-link> 
     <router-link to="/link2" tag="li" exact><a>Link 2</a></router-link> 
    </template> 

    <transition name="fade" slot="content"> 
     <router-view></router-view> 
    </transition> 

    <p slot="footer">Footer text</p> 

    </app-layout> 
</template> 

<template id="app-layout"> 
    <div class="main-container"> 

    <header class="uk-margin-bottom"> 
     <nav class="uk-navbar uk-navbar-attached"> 
     <div class="uk-navbar-brand uk-hidden-small">My Application</div> 
     <div class="uk-navbar-flip"> 
      <ul class="uk-navbar-nav uk-hidden-small"> 
      <slot name="navlinks-desktop"></slot> 
      </ul> 
      <div class="uk-navbar-toggle uk-button-dropdown uk-visible-small uk-dropdown-close" data-uk-dropdown="{mode: 'click'; justify: 'nav'}"> 
      <div class="uk-dropdown uk-dropdown-navbar uk-dropdown-small"> 
       <ul class="uk-nav uk-nav-dropdown"> 
       <slot name="navlinks-mobile"></slot> 
       </ul> 
      </div> 
      </div> 
     </div> 
     <div class="uk-navbar-brand uk-navbar-center uk-visible-small">My Application</div> 
     </nav> 
    </header> 

    <div class="uk-container uk-container-center"> 
     <main>    
     <slot name="content"></slot> 
     </main> 
    </div> 

    <footer class="uk-text-center fixed-bottom"> 
     <slot name="footer"></slot> 
    </footer> 

    </div> 
</template> 

EDIT: Alors ... Après quelques recherches et regarder de plus près à la documentation, je dois dire que ce problème spécifique N'A PAS LA SOLUTION ... Bien qu'il soit possible de réutiliser les fentes, juste rendre programatically, IL N'EST PAS POSSIBLE DE RÉUTILISER L'ESPACE AVEC LE LIEN DU ROUTEUR.

Exemple - pas de hacks - vrai "chemin Vue" de réutiliser les fentes:

<template id="app"> 
    <app-layout> 

    <template slot="myslot"> 
     <li>THIS WORKS</li> 
     <li>WILL</li> 
     <li>WORK</li> 
    </template> 

    </app-layout> 
</template> 

<script> 
    Vue.component('app-layout', { 
    render: function (createElement) { 
     var myslot = this.$slots.myslot 

     return createElement('div', [ 
     createElement('ul', myslot), 
     createElement('ul', myslot) 
     ]) 
    } 
    }) 
</script> 

est simple, élégant et facile à lire. Mais, malheureusement, si vous rendez le composant par programme, vous ne pouvez pas utiliser les modèles. Donc, quelque chose comme ça ...

<template id="app-layout"> 
    <div class="main-container"> 

    <header class="uk-margin-bottom"> 
     <nav class="uk-navbar uk-navbar-attached"> 
     <div class="uk-navbar-brand uk-hidden-small">My Application</div> 
     <div class="uk-navbar-flip"> 
      <ul class="uk-navbar-nav uk-hidden-small"> 
      <slot name="myslot"></slot> 
      </ul> 
     </div> 
     </nav> 
    </header> 

    </div> 
</template> 

... vous pouvez jeter et vous devez créer la structure entière, un par un avec la fonction createElement programatically, ce qui est vraiment painfull et sujette aux erreurs. Oui, vous pouvez utiliser JSX, mais vous devez ensuite le transférer avec Babel. Et ce n'est pas ce que je veux ... Non exemple de travail:

<template id="app"> 
    <app-layout> 

    <template slot="navlinks"> 
     <router-link to: "/">Home</router-link> 
     <router-link to: "/products">Products</router-link> 
     <router-link to: "/about">About</router-link> 
    </template> 

    </app-layout> 
</template> 

<script> 
    Vue.component('app-layout', { 
    render: function (createElement) { 
     var navlinks = this.$slots.navlinks 

     return createElement('div', [ 
     createElement('ul', navlinks), 
     createElement('ul', navlinks) 
     ]) 
    } 
    }) 
</script> 

Dans cet exemple, la deuxième UL sera vide. Et malheureusement, du point de vue que Vue dans tous les vNodes doit être unique, il est parfaitement normal, qu'il restera vide ...

Donc le résultat est que je ne peux pas utiliser la structure comme ci-dessus. Je ne peux pas avoir le modèle app-layout pour lequel j'ai un modèle avec des éléments d'emballage. Enfin, je l'ai réécrit de cette façon:

<template id="app"> 
    <div class="main-container"> 

    <header class="uk-margin-bottom"> 
     <nav class="uk-navbar uk-navbar-attached"> 
     <div class="uk-navbar-brand uk-hidden-small">My Application</div> 
     <div class="uk-navbar-flip"> 
      <ul class="uk-navbar-nav uk-hidden-small"> 
      <router-link to="/link1" tag="li" exact><a>Link 1</a></router-link> 
      <router-link to="/link2" tag="li" exact><a>Link 2</a></router-link> 
      </ul> 
      <div class="uk-navbar-toggle uk-button-dropdown uk-visible-small uk-dropdown-close" data-uk-dropdown="{mode: 'click'; justify: 'nav'}"> 
      <div class="uk-dropdown uk-dropdown-navbar uk-dropdown-small"> 
       <ul class="uk-nav uk-nav-dropdown"> 
       <router-link to="/link1" tag="li" exact><a>Link 1</a></router-link> 
       <router-link to="/link2" tag="li" exact><a>Link 2</a></router-link> 
       </ul> 
      </div> 
      </div> 
     </div> 
     <div class="uk-navbar-brand uk-navbar-center uk-visible-small">My Application</div> 
     </nav> 
    </header> 

    <div class="uk-container uk-container-center"> 
     <main>    
     <transition name="fade" slot="content"> 
      <router-view></router-view> 
     </transition> 
     </main> 
    </div> 

    <footer class="uk-text-center fixed-bottom"> 
     <p slot="footer">Footer text</p> 
    </footer> 

    </div> 
</template> 

Pas deux modèles séparés, pas d'emplacements. Mais pas de rendu de template programmatique aussi. J'ai donc gardé mon application exemple propre et facile à comprendre. Et ce fut le point ...

PS: ENCORE, JE SERAI TRES HEUREUX, SI JE SUIS MAL ET QUELQU'UN MONTRE-MOI COMMENT RÉUTILISER L'APPAREIL AVEC LE LIEN DE ROUTEUR. EDIT2: J'ai donné un coup de pied à Uikit et utilisé Bulma à la place. Cela me permet de créer une structure meilleure et plus lisible.

<!-- APPLICATION VIEW --> 
    <template id="app"> 
    <app-layout> 

     <template slot="navbar-items"> 
     <router-link to="/" class="navbar-item" exact>Home</router-link> 
     <router-link to="/about" class="navbar-item" exact>About</router-link> 
     </template> 

     <transition name="fade" mode="out-in" slot="content"> 
     <keep-alive> 
      <router-view></router-view> 
     </keep-alive> 
     </transition> 

     <p slot="footer">&copy;2017 Wal De Mar</p> 

    </app-layout> 
    </template> 
<!-- APPLICATION VIEW --> 

<!-- TEMPLATE FOR APP VIEW --> 
    <template id="app-layout"> 
    <div class="container"> 

     <header> 
     <nav class="navbar"> 
      <div class="navbar-brand"> 
      <a href="/" class="navbar-item">BRAND</a> 
      <div class="navbar-burger" data-target="main-menu"> 
       <span></span> 
       <span></span> 
       <span></span> 
      </div> 
      </div> 
      <div id="main-menu" class="navbar-menu"> 
      <div class="navbar-end"> 
       <slot name="navbar-items"></slot> 
      </div> 
      </div> 
     </nav> 
     </header> 

     <main> 
     <slot name="content"></slot> 
     </main> 

     <footer> 
     <slot name="footer"></slot> 
     </footer> 

    </div> 
    </template> 
<!-- TEMPLATE FOR APP VIEW --> 

<script> 
    Vue.component('app-layout', { 
    template: '#app-layout' 
    }) 

    new Vue({ 
    template: '#app', 
    router, 
    }).$mount('#app') 
</script> 
+1

Construire les éléments de menu comme propre composant et ajoutez simplement la composant dans la fente? –

+0

Utilisez JavaScript, v-for. –

+0

V-pour? Hmmm ... ça semble prometteur ... Mais comment? Un exemple? Ou lien vers l'exemple? – WaldemarIce

Répondre

-1

Vous pouvez créer un composant séparé qui contient les liens de navigation et l'utiliser à la place des emplacements.

<!-- NavLinks.vue --> 
<template> 
    <router-link to="/link1" tag="li" exact><a>Link 1</a></router-link> 
    <router-link to="/link2" tag="li" exact><a>Link 2</a></router-link> 
</template> 

<template id="app"> 
    <app-layout> 
    <transition name="fade" slot="content"> 
     <router-view></router-view> 
    </transition> 

    <p slot="footer">Footer text</p> 

    </app-layout> 
</template> 

<template id="app-layout"> 
    <div class="main-container"> 

    <header class="uk-margin-bottom"> 
     <nav class="uk-navbar uk-navbar-attached"> 
     <div class="uk-navbar-brand uk-hidden-small">My Application</div> 
     <div class="uk-navbar-flip"> 
      <ul class="uk-navbar-nav uk-hidden-small"> 
      <nav-links></nav-links> 
      </ul> 
      <div class="uk-navbar-toggle uk-button-dropdown uk-visible-small uk-dropdown-close" data-uk-dropdown="{mode: 'click'; justify: 'nav'}"> 
      <div class="uk-dropdown uk-dropdown-navbar uk-dropdown-small"> 
       <ul class="uk-nav uk-nav-dropdown"> 
       <nav-links></nav-links> 
       </ul> 
      </div> 
      </div> 
     </div> 
     <div class="uk-navbar-brand uk-navbar-center uk-visible-small">My Application</div> 
     </nav> 
    </header> 

    <div class="uk-container uk-container-center"> 
     <main>    
     <slot name="content"></slot> 
     </main> 
    </div> 

    <footer class="uk-text-center fixed-bottom"> 
     <slot name="footer"></slot> 
    </footer> 

    </div> 
</template> 
+0

Êtes-vous vraiment sûr de cela? – WaldemarIce

+0

>>> Dupliquer la présence du slot "navlinks" trouvé dans le même arbre de rendu - ceci provoquera probablement des erreurs de rendu. <<< – WaldemarIce

+0

@WaldemarIce J'ai mis à jour ma réponse pour utiliser des composants au lieu de slots. – Nora

0

Vous pouvez utiliser un emplacement nommé plusieurs fois. Dans l'extrait ci-dessous, j'ai un composant qui prend deux slots et un autre composant qui le nourrit deux fois dans le même slot.

Vue.component('twoMenus', { 
 
    template: '#two-menu-template' 
 
}); 
 

 
new Vue({ 
 
    el: '#app', 
 
    components: { 
 
    slotDoubler: { 
 
     template: '#slot-doubler-template' 
 
    } 
 
    } 
 
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script> 
 
<div id="app"> 
 
    <two-menus> 
 
    <div slot="menu1">I am a menu</div> 
 
    <div slot="menu2">I am a different menu</div> 
 
    </two-menus> 
 
    <hr> 
 
    <slot-doubler> 
 
    <div slot="reusable">This menu appears twice!</div> 
 
    </slot-doubler> 
 
</div> 
 

 
<template id="two-menu-template"> 
 
    <div> 
 
    <div>The first menu is here: 
 
     <slot name="menu1"></slot> 
 
    </div> 
 
    <div>And the second is here: 
 
     <slot name="menu2"></slot> 
 
    </div> 
 
    </div> 
 
</template> 
 

 
<template id="slot-doubler-template"> 
 
    <div> 
 
    <two-menus> 
 
     <div slot="menu1"> 
 
     <slot name="reusable"></slot> 
 
     </div> 
 
     <div slot="menu2"> 
 
     <slot name="reusable"></slot> 
 
     </div> 
 
    </two-menus> 
 
    </div> 
 
</template>

0

si je dois remplir deux menus avec une donnée que je voudrais aller avec un autre beaucoup plus facile et une bonne approche.

vous pouvez avoir un objet de menu javascript et via v-for remplir les éléments de menu. vous pouvez avoir un accès complet à votre dom et le manipuler comme vous le souhaitez.J'ai écrit une petite démo pour vous ci-dessous

si vous avez besoin de dupliquer vous pouvez déplacer le modèle v-for à un component et passer l'objet de menu pour ce

new Vue({ 
 
    el:"#app", 
 
    data : { 
 
    menu : [ 
 
     { 
 
     // have each menu item as js object 
 
     text : 'Home', 
 
     to : { name : 'somewhere'}, 
 
     href : '/somewhere' 
 
     }, 
 
     { 
 
     // you can even have a divider 
 
     divider : true 
 
     }, 
 
     { 
 
     text : 'About', 
 
     to : { name : 'somewhere'}, 
 
     href : '/somewhere' 
 
     }, 
 
     { 
 
     // have each menu item as js object 
 
     text : 'Services', 
 
     to : { name : 'somewhere'}, 
 
     href : '/somewhere', 
 
     children : [ 
 
      // you can even have child menu 
 
     ] 
 
     }, 
 
    ] 
 
    } 
 
})
.mobile-menu { 
 
    background : grey; 
 
    border : black solid 3px; 
 
}
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script> 
 
<div id="app"> 
 

 
    
 
    <ul class="desktop-menu"> 
 
    <template v-for="item in menu"> 
 
     <li v-if="item.divider"> 
 
     <span class="divider" >--------</span> 
 
     </li> 
 
     <li v-else> 
 
     <router-link :to="item.to" v-text="item.text"></router-link> 
 
     </li> 
 
    </template> 
 
    </ul> 
 
    
 
    <ul class="mobile-menu"> 
 
    <template v-for="item in menu"> 
 
     <li v-if="item.divider"> 
 
     <span class="divider" >--------</span> 
 
     </li> 
 
     <li v-else> 
 
     <router-link :to="item.to" v-text="item.text"></router-link> 
 
     </li> 
 
    </template> 
 
    </ul> 
 
</div>

0

Si je comprends votre exigence, vous pouvez utiliser la même fente un certain nombre de fois.

copie juste et coller le même emplacement en deux endroits

`` `html

<header class="uk-margin-bottom"> 
    <nav class="uk-navbar uk-navbar-attached"> 
    <div class="uk-navbar-brand uk-hidden-small">My Application</div> 
    <div class="uk-navbar-flip"> 
     <ul class="uk-navbar-nav uk-hidden-small"> 
     <slot name="navlinks-desktop"></slot> 
     </ul> 
     <div class="uk-navbar-toggle uk-button-dropdown uk-visible-small uk-dropdown-close" data-uk-dropdown="{mode: 'click'; justify: 'nav'}"> 
     <div class="uk-dropdown uk-dropdown-navbar uk-dropdown-small"> 
      <ul class="uk-nav uk-nav-dropdown"> 
     <slot name="navlinks-desktop"></slot> 
      </ul> 
     </div> 
     </div> 
    </div> 
    <div class="uk-navbar-brand uk-navbar-center uk-visible-small">My Application</div> 
    </nav> 
</header> 

<div class="uk-container uk-container-center"> 
    <main>    
    <slot name="content"></slot> 
    </main> 
</div> 

<footer class="uk-text-center fixed-bottom"> 
    <slot name="footer"></slot> 
</footer> 

` ``

+0

Cela ne fonctionne pas si vous passez des liens de routeur à l'emplacement. Les liens de routeur ne seront rendus que dans le premier emplacement. – WaldemarIce