Vue - какой-нибудь способ повторно использовать слот?

1

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">&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.
Показать ещё 3 комментария
Теги:
vue.js
vuejs2
uikit
vue-component

4 ответа

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
    Это не работает, если вы передаете ссылки маршрутизатора в слот. Ссылки на маршрутизаторы будут отображаться только в первом слоте.
0

если мне нужно заполнить два меню одной информацией, я бы пошел с другим гораздо более простым и хорошим подходом.

вы можете иметь объект меню 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>
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

Вы можете создать отдельный компонент, который содержит ссылки навигации, и использовать его вместо слотов.

<!-- 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
    Вы действительно уверены в этом?
  • 0
    >>> Двойное присутствие слота "navlinks", найденного в том же дереве рендера - это, вероятно, приведет к ошибкам рендеринга. <<<
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню