2017-07-27 46 views
1

林与UIKit的响应Vue.js应用工作。我必须创建2个菜单 - 一个用于桌面版本,另一个用于移动版本。所以我必须定义相同的菜单项2次,第一次用于桌面链接插槽,第二次用于移动。我不想把它定义为2x。我如何优雅地处理这个问题?有任何想法吗?Vue - 任何重用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> 

编辑:那么......经过一番研究,仔细看看文档,我必须说,这个具体的问题没有解决方案...虽然可以重复使用插槽,只是使其编程,它不可能通过路由器链接重新使用SLOT。

实施例 - 无黑客 - 真 “的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公司的所有虚拟节点必须是唯一的,这是完全正常的,它仍将是空的......

所以结果是我无法用结构如上。我不能有模板应用程序布局,我有模板与包装元素。最后,我以这种方式重写:

<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和使用布尔玛代替。这使我可以创建更好,更可读的结构。

<!-- 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

构建菜单项为自己的组件,只是添加组件插入插槽? –

+0

使用JavaScript,v-for。 –

+0

V-for?嗯......听起来很有希望......但是怎么样?任何示例?或者链接到例子? – WaldemarIce

回答

-1

你可以创建一个包含导航链接单独的组件,并用它代替插槽。

<!-- 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

你确定吗? – WaldemarIce

+0

>>>在同一个渲染树中发现插槽“navlinks”的重复 - 这可能会导致渲染错误。 <<< – WaldemarIce

+0

@WaldemarIce我已更新我的答案,以使用组件而不是插槽。 – Nora

0

您可以多次使用一个命名槽。在下面的代码片段中,我有一个组件需要两个插槽,另一个组件将两个相同的插槽提供给它。

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

,如果我需要填充两个菜单与一个数据我会去另一个更容易和好方法。

你可以有一个JavaScript菜单对象,并通过v-for填充菜单项。你可以完全访问你的dom并按照你的意愿操作它。我已经写了一个小演示下面为您

,如果你需要复制就可以了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>

0

如果我没有理解您的要求,您可以在任何时间使用相同的插槽。

只需复制并粘贴在两个地方

相同的插槽```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

如果您将路由器链接传递给插槽,则不起作用。路由器链路将仅在第一个时隙中呈现。 – WaldemarIce