Im работает на отзывчивое приложение Vue.js с Uikit. Я должен создать 2 меню - один для настольной версии, один для мобильного. Поэтому я должен определить одинаковые пункты меню 2 раза, сначала для слота для настольных ссылок, второй раз для мобильных устройств. Я не хочу определить его 2x. Как я могу справиться с этой проблемой элегантно? Есть идеи?
<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: Итак... После некоторых исследований и более пристального взгляда на документацию, я должен сказать, что эта конкретная проблема НЕ ИМЕЕТ РЕШЕНИЯ... Хотя можно использовать слоты для повторного использования, просто визуализируйте ее программно, НЕ ВОЗМОЖНО ВОЗВРАТАТЬ СЛОТ С РУЧНОЙ СВЯЗЬЮ.
Пример - без хаков - true "Vue way" для повторного использования слотов:
<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>
Его простой, элегантный и читаемый. Но, к сожалению, если вы программно обрабатываете компонент, вы не можете использовать шаблоны. Так что-то вроде этого...
<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>
... вы можете выбросить, и вы должны создать целую структуру, один за другим, программно с помощью функции createElement, которая очень болезненна и подвержена ошибкам. Да, вы можете использовать JSX, но тогда вы должны перевести его с помощью Babel. И это не то, что я хочу... Нерабочий пример:
<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>
В этом примере второй UL будет пустым. И, к сожалению, с точки зрения факта, что в Vue все vNodes должны быть уникальными, это совершенно нормально, что он останется пустым...
В результате я не могу использовать структуру, как указано выше. Я не могу иметь шаблонный макет приложения, для которого у меня есть шаблон с элементами упаковки. Наконец, я переписал это так:
<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>
Нет двух отдельных шаблонов, нет слотов. Но никакого программного преобразования шаблона тоже нет. Поэтому я оставил свое примерное приложение понятным и понятным. И в этом был смысл...
PS: ВСЕ ЕЩЕ, Я БУДЕТ ОЧЕНЬ СЧАСТЛИВЫМ, ЕСЛИ Я НЕПРАВИЛЬНО, И КОТОРЫЙ ПОКАЗЫВАЮТ МЕНЯ, КАК ВОЗВРАТИТЬ СЛОВО С МАРШРУТИЗАТОРОМ.
EDIT2: Я пнул Uikit и вместо этого использовал Bulma. Это позволяет мне создавать лучшую, более читаемую структуру.
<!-- 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">©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>
Если я понимаю ваше требование, вы можете использовать один и тот же слот в любое время.
просто скопируйте и вставьте тот же слот в два места
'' '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>
"""
если мне нужно заполнить два меню одной информацией, я бы пошел с другим гораздо более простым и хорошим подходом.
вы можете иметь объект меню javascript и через v-for
заполнения пунктов меню. вы можете иметь полный доступ к вашему дому и управлять им, как хотите. я написал немного демо для вас ниже
если вам нужно дублировать, вы можете переместить шаблон v-for
в component
и передать ему объект меню
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>
Вы можете использовать именованный слот более одного раза. В нижеприведенном фрагменте у меня есть компонент, который принимает два слота и другой компонент, который передает его в один и тот же слот дважды.
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>
Вы можете создать отдельный компонент, который содержит ссылки навигации, и использовать его вместо слотов.
<!-- 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>