【发布时间】:2018-01-03 08:25:46
【问题描述】:
我正在使用 Uikit 开发响应式 Vue.js 应用程序。我必须创建 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>
编辑:所以...经过一些研究和仔细查看文档后,我必须说,这个特定问题没有解决方案...虽然可以重用插槽,但只需以编程方式呈现它,这是不可能的使用路由器链接重用插槽。
示例 - 没有 hack - 真正的“Vue 方式”重用插槽:
<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 中所有 vNode 都必须是唯一的,这是完全正常的,它将保持为空......
所以结果是我不能使用上面的结构。我不能有模板应用程序布局,我有带有包装元素的模板。最后,我改写成这样:
<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>
【问题讨论】:
-
将菜单项构建为自己的组件,然后将组件添加到插槽中?
-
使用 JavaScript,v-for.
-
V-for?嗯……听起来很有希望……但是怎么做呢?有什么例子吗?或链接到示例?
-
嗨,
navlinks-desktop和navlinks-mobile看起来完全一样。为什么不只使用一个名为navlinks的插槽并在不同的菜单包装器中使用它? -
是的,这就是我想要的。但是怎么做?你能重写我的模板吗?
标签: javascript vue.js uikit vuejs2 vue-component