Переключение шаблона страниц во vuejs

от автора

Иногда в приложении требуется шаблоны для различных страниц, чтобы не копировать код от компонента к компоненту, мы прописываем шаблон в основном компоненте (он же, обычно, App.vue) и с помощью <router-view> подставляем в него различные вьюшки.

image

Как мы видим, у различных страниц общая шапка. Сайт.

А что, если нам необходимо сделать несколько шаблонов для разных страниц или состояний приложения? Этим мы сейчас и займемся.

Первым делом нам необходимо Vue Js приложение с подключенным роутером.

Что из себя представляют шаблоны? Правильно, обычные компоненты, которые будут вызываться в зависимости от того или иного условия, будь то активная странница, статус аутентификации или (по бреду) время суток.

Подготовим основной компонент для работы с шаблонами.

Если вы создавали проект через Vue-Cli у вас он выглядит примерно так:

//ВАШ_ПРОЕКТ/src/App.vue  <template>   <div id="app">     <div id="nav">       <router-link to="/">Home</router-link> |       <router-link to="/about">About</router-link>     </div>     <router-view/>   </div> </template>  <style> #app {   font-family: Avenir, Helvetica, Arial, sans-serif;   -webkit-font-smoothing: antialiased;   -moz-osx-font-smoothing: grayscale;   text-align: center;   color: #2c3e50; }  #nav {   padding: 30px; }  #nav a {   font-weight: bold;   color: #2c3e50; }  #nav a.router-link-exact-active {   color: #42b983; } </style> 

Нам необходимо добавить новое вычисляемое свойство (Computed) в секцию «script» (если у вас ее нет, скопируйте ее из любого vue компонента).

Это свойство будет возвращать нам имя компонента-шаблона в зависимости от того или иного условия, в данном примере — шаблон будет привязан к странице.

//ВАШ_ПРОЕКТ/src/App.vue ...  <script>     export default {         computed: {             //Это самое вычисляемое свойство             layout(){                 //Вернем имя шаблона из роута или дефолтное значение                    //(шаблон для страниц, для которых мы не указали шаблон)                 return this.$route.meta.layout || "default-layout"              }         }     } </script>  ... 

Отредактируем секцию «template» — добавим в нее динамический компонент, который будет меняться в зависимости от значения layout.

//ВАШ_ПРОЕКТ/src/App.vue  <template>   <div id="app">       <!--Динамический компонент-->       <component :is="layout">           <router-view/>       </component>   </div> </template>  ... 

Теперь создадим пару шаблонов.

Для удобства будем хранить их в отдельной папке «layouts».

скриншот структуры папкок

По значимости папка не сильно ушла от components или view, просто удобно.

Есть у Vue такой элемент — «slot», который позволит нам подставлять наши представления в компонент-шаблон. При отрисовке он заменяется на контент, который мы укажем при вызове компонента. Создадим три шаблона, пусть они будут одинаковыми, с разницей в цвете шапки и подвала, для наглядности.

Синий шаблон, дефолтный:

//ВАШ_ПРОЕКТ/src/layouts/Default.vue  <template>     <div>         <header>             <ul class="nav">                 <li><router-link class="link" to="/">Домашняя страница</router-link></li>                 <li><router-link class="link" to="/page2">Страница 1</router-link></li>                 <li><router-link class="link" to="/page3">Страница 2</router-link></li>                 <li><router-link class="link" to="/page4">Страница 2</router-link></li>             </ul>         </header>         <section class="content">              <!--Элемент, который при отрисовке будет заменен на ваш view-->             <slot/>          </section>         <footer>          </footer>     </div> </template>  <script>     export default {         name: "Default"     } </script>  <style scoped>     header{         background-color: blue;         height: 70px;         display: flex;         align-items: center;     }      footer{         background-color: blue;         height: 70px;     }      .content{         min-height: calc(100vh - 140px);     }      ul{         list-style: none;         margin: 0;         color: white;     }      li{         color: white;         display: inline;         margin: 0 5px;     }      .link{         color: white;         text-decoration: none;     }  </style> 

Зеленый шаблон:

//ВАШ_ПРОЕКТ/src/layouts/Green.vue  <template>     <div>         <header>             <ul class="nav">                 <li><router-link class="link" to="/">Домашняя страница</router-link></li>                 <li><router-link class="link" to="/page2">Страница 1</router-link></li>                 <li><router-link class="link" to="/page3">Страница 2</router-link></li>                 <li><router-link class="link" to="/page4">Страница 2</router-link></li>             </ul>         </header>         <section class="content">              <!--Элемент, который при отрисовке будет заменен на ваш view-->             <slot/>          </section>         <footer>          </footer>     </div> </template>  <script>     export default {         name: "green"     } </script>  <style scoped>     header{         background-color: green;         height: 70px;         display: flex;         align-items: center;     }      footer{         background-color: green;         height: 70px;     }      .content{         min-height: calc(100vh - 140px);     }      ul{         list-style: none;         margin: 0;         color: white;     }      li{         color: white;         display: inline;         margin: 0 5px;     }      .link{         color: white;         text-decoration: none;     }  </style> 

Красный шаблон:

//ВАШ_ПРОЕКТ/src/layouts/Red.vue  <template>     <div>         <header>             <ul class="nav">                 <li><router-link class="link" to="/">Домашняя страница</router-link></li>                 <li><router-link class="link" to="/page2">Страница 1</router-link></li>                 <li><router-link class="link" to="/page3">Страница 2</router-link></li>                 <li><router-link class="link" to="/page4">Страница 2</router-link></li>             </ul>         </header>         <section class="content">              <!--Элемент, который при отрисовке будет заменен на ваш view-->             <slot/>          </section>         <footer>          </footer>     </div> </template>  <script>     export default {         name: "Red"     } </script>  <style scoped>     header{         background-color: red;         height: 70px;         display: flex;         align-items: center;     }      footer{         background-color: red;         height: 70px;     }      .content{         min-height: calc(100vh - 140px);     }      ul{         list-style: none;         margin: 0;         color: white;     }      li{         color: white;         display: inline;         margin: 0 5px;     }      .link{         color: white;         text-decoration: none;     }  </style> 

Теперь зарегистрируем эти компоненты-шаблоны в нашем Vue.

//ВАШ_ПРОЕКТ/src/main.js  import Vue from 'vue' import App from './App.vue' import router from './router' //Подключим файлы компонентов import DefaultLayout from "./layouts/Default" import GreenLayout from "./layouts/Green" import RedLayout from "./layouts/Red"  //И зарегистрируем их в нашем приложении Vue.component("default-layout", DefaultLayout) Vue.component("green-layout", GreenLayout) Vue.component("red-layout", RedLayout)  Vue.config.productionTip = false  new Vue({   router,   render: h => h(App) }).$mount('#app') 

Отлично! Шаблоны готовы, давайте создадим четыре представления(страницы), два из которых будут отрисовываться с синим шаблоном, а два остальных с красным и зеленым. Они тоже будут одинаковыми, только с разными заголовками.

//ВАШ_ПРОЕКТ/src/views/page1.vue  <template>     <div>         <h1>Синий шаблон</h1>     </div> </template>  <script>     export default {         name: "Page1"     } </script>  <style scoped> 

</style> //ВАШ_ПРОЕКТ/src/views/page2.vue  <template>     <div>         <h1>Зеленый шаблон</h1>     </div> </template>  <script>     export default {         name: "Page2"     } </script>  <style scoped>  </style> 

//ВАШ_ПРОЕКТ/src/views/page3.vue  <template>     <div>         <h1>Красный шаблон</h1>     </div> </template>  <script>     export default {         name: "Page3"     } </script>  <style scoped>  </style>  

//ВАШ_ПРОЕКТ/src/views/page4.vue  <template>     <div>         <h1>Еще один синий шаблон</h1>     </div> </template>  <script>     export default {         name: "Page4"     } </script>  <style scoped>  </style> 

Теперь добавим роуты под наши страницы, и в мета-данных укажем какой шаблон им использовать при отрисовке.

import Vue from 'vue' import VueRouter from 'vue-router' //Подключим наши страницы import Page1 from "../views/Page1" import Page2 from "../views/Page2" import Page3 from "../views/Page3" import Page4 from "../views/Page4"  Vue.use(VueRouter)  const routes = [     {         path: '/',         name: 'Home',         component: Page1         //Так, как синий шаблон у нас является дефолтным, его можно не указывать в мета-данных     },     {         path: '/page2',         name: 'Page2',         component: Page2,         //А вот это свойство как раз будет содержать название компонента-шаблона,         //который мы хотим использовать для данной страницы         meta:{             layout: "green-layout"         }     },     {         path: '/page3',         name: 'Page3',         component: Page3,         meta:{             layout: "red-layout"         }     },     {         path: '/page4',         name: 'Page4',         component: Page4,         //И снова ничего не указываем, чтобы задействовать дефолтный шаблон     } ]  const router = new VueRouter({     mode: 'history',     base: process.env.BASE_URL,     routes })  export default router 

Запускаем наше приложение и проверяем:

image

Целиком код можно посмотреть тут

ссылка на оригинал статьи https://habr.com/ru/post/513728/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *