лицом к макету
Начну с вопроса:
«Как вы думаете, что-то не так с настройками макетов в вашем текущем проекте Vue?»
Вы можете ответить:
«Нет проблем. Разве это не просто компонент Layout на внешнем слое?»
Я думаю, что это должно быть что-то вроде этого:
<template>
<MyLayout>
<h1>Here is my page content</h1>
</MyLayout>
</template>
<script>
import MyLayout from '@/layouts/MyLayout.vue'
export default {
name: 'MyPage',
components: { MyLayout }
}
</script>
Или вот так, например, проект Bengua, Настройки макета:
- Если вы использовали vue-element-admin, вы должны быть знакомы с такими настройками маршрутизации (бизнес-компоненты являются подкомпонентами компонентов макета).
const AdminLayout = () => import('@/views/admin/homepage/layout.vue')
const OrgList = () => import('@/views/admin/admOrg/orgList.vue')
const OrgDetail = () => import('@/views/admin/admOrg/orgDetail.vue')
export const admOrgRouters = {
path: '/orgManage',
component: AdminLayout,
redirect: '/orgList',
name: '组织管理',
iconClass: 'orgManage',
children: [
orgList,
orgDetail,
],
meta: {
roles: ['isAdmin', 'ordinaryAdmin'],
title: '组织管理'
}
}
Приятно! Если ваш проект похож на этот, вы можете продолжить чтение следующей статьи~ (иначе просто поставить лайк 👍 и закрыть ❎ выход 😄)
Найдите болевые точки
Вроде бы нет ничего плохого в установке Layout во внешнем пакете, но давайте подумаем:
- Нам нужно импортировать макет на разные страницы, а «повторное введение» всегда является одной из самых раздражающих вещей для программистов;
- Мы должны сделать так, чтобы макет обертывал наш контент, что несколько ограничено;
- Это утяжеляет наш код и вынуждает компонент брать на себя ответственность за отрисовку макета (компонент и макет недостаточно разделены);
Хотя это не очень большие моменты, но из-заNuxtJS, поэтому мы решили провестиbreaking change, чтобы изменить эту ситуацию.
Это nuxtjs именно то, что вдохновило его? Короче, а именно:
Вы можете определить [макет] как [свойство] компонента, вместо того, чтобы устанавливать родительский компонент макета для вашего приложения.
Прикрепил:nuxtjs-layouts
Давайте посмотрим, как это вдохновение может быть реализовано в нашем проекте Vue?
Подготовка проекта
Мы по-прежнему используем Vue CLI для быстрой сборки наших проектов:
vue create vue-layouts
Вы можете выбрать Vue2+ или Vue3+, в этой статье будет описано соответственно.
Мы очищаем некоторые ненужные файлы, принесенные инициализацией, такие какHelloWorld.vue
, а затем создайте новый файл, чтобы получить этот каталог:
--src
----views
------About.vue
------Contacts.vue
------Home.vue
----App.vue
----main.js
----router.js
Тогда в App.vue код такой:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/contacts">Contacts</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>
Код Home.vue выглядит следующим образом:
<template>
<div>
<h1>This is a home page</h1>
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
Код About.vue выглядит следующим образом:
<template>
<div>
<h1>This is an about page</h1>
</div>
</template>
<script>
export default {
name: 'About'
}
</script>
Код Contacts.vue выглядит следующим образом:
<template>
<div>
<h1>This is a contacts page</h1>
</div>
</template>
<script>
export default {
name: "Contacts"
}
</script>
Код router.js выглядит следующим образом:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue')
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue')
},
{
path: '/contacts',
name: 'Contacts',
component: () => import('@/views/Contacts.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
Затем вызовите маршрутизатор в main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router: router
}).$mount('#app')
Что ж, подготовка завершена. Мы можем получить такой интерфейс:
Это три простых перехода маршрутизации и коммутация компонентов. Здесь не будет проблем~
Построить макет
Дело пикантное!
мы создаем новыйlayouts/AppLayout.vueкомпоненты.
- Vue2
<template>
<component :is="layout">
<slot />
</component>
</template>
<script>
const defaultLayout = 'AppLayoutDefault'
export default {
name: "AppLayout",
computed: {
layout() {
const layout = this.$route.meta.layout || defaultLayout
return () => import(`@/layouts/${layout}.vue`)
}
}
}
</script>
Этот фрагмент кода может показаться простым, но он является частью нашей новой системы компоновки.основной!
В этом шаблоне мы добавилидинамические компонентыи добавьте к нему вычисляемое свойство с именем layout.
При расчете свойства мы видим, что он вернет [] [в соответствии с компонентами макета маршрутизации, соответствующими [Динамическому] и загрузит сборку], чтобы перейти, в противном случае включите макет по умолчанию — defaultLayout.
- Код в Vue3 выглядит следующим образом:
<template>
<component :is="layout">
<slot />
</component>
</template>
<script>
import AppLayoutDefault from './AppLayoutDefault'
export default {
name: "AppLayout",
data: () => ({
layout: AppLayoutDefault
}),
watch: {
$route: {
immediate: true,
async handler(route) {
try {
const component = await import(`@/layouts/${route.meta.layout}.vue`)
this.layout = component?.default || AppLayoutDefault
} catch (e) {
this.layout = AppLayoutDefault
}
}
}
}
}
</script>
Реализация Vue 3 Composition API:
<template>
<component :is="layout">
<slot />
</component>
</template>
<script>
import AppLayoutDefault from './AppLayoutDefault'
import { markRaw, watch } from 'vue'
import { useRoute } from 'vue-router'
export default {
name: 'AppLayout',
setup() {
const layout = markRaw(AppLayoutDefault)
const route = useRoute()
watch(
() => route.meta,
async meta => {
try {
const component = await import(`@/layouts/${meta.layout}.vue`)
layout.value = component?.default || AppLayoutDefault
} catch (e) {
layout.value = AppLayoutDefault
}
},
{ immediate: true }
)
return { layout }
}
}
</script>
Несколько макетов
Опираясь на суть предыдущего раздела, давайте посмотрим, как мы можем улучшить нашу систему компоновки~
Помните три основных компонента, которые мы подготовили при инициализации:Home
,About
,Contacts
, к которому мы готовимсяСоздайте три макета. (Конечно, вы можете настроить столько макетов, сколько захотите.)
Перед этим делаем небольшой рефакторинг App.vue:
Создайте новый файл:layouts/AppLayoutLinks.vue, извлеките сюда код App.vue, оставив чистый файл App.vue.
// Новый AppLayoutLinks.vue
<template>
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/contacts">Contacts</router-link>
</div>
</template>
<script>
export default {
name: "AppLayoutLinks"
}
</script>
<style scoped>
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
</style>
// очищаем App.vue
<template>
<div id="app">
<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;
}
</style>
Затем создайте три файла макета~
- Первый метод макета: AppLayoutHome.vue
<template>
<div>
<header class="header" />
<AppLayoutLinks />
<slot />
</div>
</template>
<script>
import AppLayoutLinks from '@/layouts/AppLayoutLinks'
export default {
name: "AppLayoutHome",
components: {
AppLayoutLinks
}
}
</script>
<style scoped>
.header {
height: 5rem;
background-color: green;
}
</style>
- Метод макета 2: AppLayoutAbout.vue
<template>
<div>
<header class="header" />
<AppLayoutLinks />
<slot />
</div>
</template>
<script>
import AppLayoutLinks from '@/layouts/AppLayoutLinks'
export default {
name: "AppLayoutAbout",
components: {AppLayoutLinks}
}
</script>
<style scoped>
.header {
height: 5rem;
background-color: blue;
}
</style>
- Третий метод макета: AppLayoutContacts
<template>
<div>
<header class="header" />
<AppLayoutLinks />
<slot />
</div>
</template>
<script>
import AppLayoutLinks from '@/layouts/AppLayoutLinks'
export default {
name: "AppLayoutContacts",
components: {
AppLayoutLinks
}
}
</script>
<style scoped>
.header {
height: 5rem;
background-color: red;
}
</style>
Здесь демонстрационная раскладка отличается простыми цветовыми различиями, в основном «знающими». Макет по умолчанию не меняет цвет и не будет вдаваться в подробности.
Настроить маршрутизацию
если внимательно посмотретьПостроить макетВы, должно быть, видели суть этогоthis.$route.meta.layoutэтот звонок. Значит нам нужно вернуть маршрут в set, код такой:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/Home.vue'),
meta: {
layout: 'AppLayoutHome'
}
},
{
path: '/about',
name: 'About',
component: () => import('@/views/About.vue'),
meta: {
layout: 'AppLayoutAbout'
}
},
{
path: '/contacts',
name: 'Contacts',
component: () => import('@/views/Contacts.vue'),
meta: {
layout: 'AppLayoutContacts'
}
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
Завершить работу
Все вышеперечисленное настроено, и, наконец, нам нужно связать AppLayout.vue с App.vue:
<div id="app">
<AppLayout>
<router-view />
</AppLayout>
</div>
Готово!
Вы можете загрузить проект локально и запустить его:гитхаб-адрес
Таким образом, мы добилисьновая система компоновки. Вдохновленный коллекцией волос Sassoon, о нет, вдохновленный NuxtJS~ вы чувствуете это?
Подводя итог: наша предыдущая компоновка была обернута компонентами или маршрутизацией, что часто требовало нескольких ссылок. При наличии нескольких способов раскладки будет сложнее, а отдельной системы раскладки для четкого деления нет. Эта статья проходит«Динамические компоненты» + «Свойства прослушивания» + «Конфигурация маршрута» + «Глобальное монтирование»Способ извлечь систему макета, избежать множественных представлений и избежать нечеткой структуры каталогов. Было бы разумно построить этот макет в начале проекта сборки! Если это старый проект, есть различные макеты, вы можете отрефакторить его, когда у вас будет время, и почувствовать это. почему бы нет?
Писать не просто✍, ставьте лайки и поощряйте 👍, обратите внимание на мой паблик [Nuggets Anthony] 😎, искренний выход...