布局是减少代码重复并创建易于维护和专业外观的应用程序的重要模式。如果您正在使用Nuxt,它提供了一个优雅的解决方案。但不幸的是,在Vue中,官方文档根本没有提到它们。这经常导致对于应该在多个应用程序中相似的问题而言,采用次优和不太正规的解决方案。
经过多次尝试,我总结出了一种既有效又无需烦恼地扩展的布局方式。让我用一个小的示例演示一下。
首先,让我们确定一些我们的布局结构需要满足的规则:
我们需要在页面之间进行导航,这就是为什么我们要设置vue-router。 Vue-cli 和 vite 脚手架在创建新项目时提供了包含它的选项,但如果你不是从头开始,以下是安装它的步骤。
安装 vue-router 依赖
npm i -D vue-router@4
声明路由
const routes = [
{ path: "/", component: () => import("./pages/HomePage.vue") },
{ path: "/explore", component: () => import("./pages/ExplorePage.vue") },
];
导入项目
import { createApp } from "vue";
import { createRouter, createWebHashHistory } from "vue-router";
import App from "./App.vue";
import routes from "./routes.ts"
const router = createRouter({
history: createWebHashHistory(),
routes,
});
const app = createApp(App);
app.use(router);
app.mount("#app");
最后,更新App.vue文件,只包含一个 router-view 标签。
<template>
<router-view />
</template>
我们现在可以在两个页面之间导航了,但这并不令人兴奋,因为它们目前是空的。让我们改变这种情况。
我们将创建以下页面:首页、Explore、文章和404。还有三种布局:三列、两列和空白。
主页是每个流行社交网络都使用的典型三栏布局。第一栏包含应用程序的标志和导航,这在使用此布局的每个页面上都保持不变。底部右侧的页脚也是如此。主要内容和侧边栏小部件在每个页面上都会有所变化。
让我们从 HomePage.vue 组件开始实施。
<script setup lang="ts">
import ThreeColumnLayout from "../layouts/ThreeColumnLayout.vue";
import ArticleCard from "../components/ArticleCard.vue";
import WidgetFriendSuggestions from "../components/WidgetFriendSuggestions.vue";
import useArticles from "../composables/useArticles";
const articles = useArticles().getArticles();
</script>
<template>
<ThreeColumnLayout>
<h2 class="text-3xl font-bold mb-4">Homepage content</h2>
<ArticleCard v-for="article in articles" :article="article" />
<template #aside>
<WidgetFriendSuggestions />
</template>
</ThreeColumnLayout>
</template>
我们将很快实现一个 ThreeColumnLayout 组件。默认插槽包含一个标题和一系列文章,这些文章是页面的主要内容。此外,我们还有一个名为 aside 的具名插槽,用于声明一个小部件。
按照通常的约定, ThreeColumnLayout 组件被放置在 /layouts 文件夹中。它将使用网格容器,并利用 grid-template-areas 来创建一个三列布局。
布局的实现细节应该是该组件的关注点,而不是页面的关注点。可以使用flexbox、网格系统或任何其他技术来实现。如果使用全宽、盒状或流体布局,同样适用。
这个布局有3列
<script setup>
import AppNavigation from "../components/AppNavigation.vue";
import AppFooter from "../components/AppFooter.vue";
import AppLogo from "../components/AppLogo.vue";
</script>
<template>
<div class="three-column-layout">
<header>
<AppLogo />
<AppNavigation />
</header>
<main>
<slot />
</main>
<aside>
<slot name="aside" />
<AppFooter />
</aside>
</div>
</template>
<style scoped lang="scss">
.three-column-layout {
display: grid;
grid-template-areas:
"header"
"main"
"aside";
header {
grid-area: header;
margin-top: 30px;
}
main {
grid-area: main;
margin-top: 10px;
padding: 20px;
}
aside {
grid-area: aside;
margin-top: 10px;
padding: 20px;
}
@media (min-width: 768px) {
grid-template-columns: 1fr 3fr 1fr;
grid-template-areas: "header main aside";
}
}
</style>
创建一个具有相同布局的新页面将展示出这种方法的简洁性。
文章页面还将在默认插槽中包含独特的内容,并在侧边栏上添加一个额外的小部件:
<script setup>
import ThreeColumnLayout from "../layouts/ThreeColumnLayout.vue";
import WidgetRelatedContent from "../components/WidgetRelatedContent.vue";
import WidgetFriendSuggestions from "../components/WidgetFriendSuggestions.vue";
import { useRoute } from "vue-router";
import useArticles from "../composables/useArticles";
const article = useArticles().getArticle(useRoute().params.id);
</script>
<template>
<ThreeColumnLayout>
<h2 class="text-3xl font-bold mb-4">{{ article.title }}</h2>
<div class="max-w-md" v-html="article.description"></div>
<template #aside>
<WidgetFriendSuggestions />
<WidgetRelatedContent />
</template>
</ThreeColumnLayout>
</template>
对于探索页面(Explore),我们将创建一个两列布局。第一列将与三列布局相同,但主要部分将占据屏幕的其余部分,并在底部放置页脚。
这次的实现看起来与之前的并没有太大的区别。但是这次我们使用 flex 和 flex-basis 只是为了展示一种不同的创建CSS布局的方式。在实际情况中,所有的实现都应该使用相同的技术。
<script setup>
import AppNavigation from "../components/AppNavigation.vue";
import AppLogo from "../components/AppLogo.vue";
import AppFooter from "../components/AppFooter.vue";
</script>
<template>
<div class="two-column-layout">
<header>
<AppLogo />
<AppNavigation />
</header>
<main>
<slot />
<AppFooter />
</main>
</div>
</template>
<style scoped>
.two-column-layout {
display: flex;
@media (max-width: 768px) {
flex-direction: column;
}
}
header {
flex-basis: 20%;
margin-top: 30px;
}
main {
flex-basis: 80%;
margin-top: 10px;
padding: 20px;
}
</style>
使用这种布局的探索页面非常简单
<script setup>
import TwoColumnLayout from "../layouts/TwoColumnLayout.vue";
import ExploreItem from "../components/ExploreItem.vue";
import useArticles from "../composables/useArticles";
const articles = useArticles().getExploreArticles();
</script>
<template>
<TwoColumnLayout>
<h2 class="text-3xl font-bold mb-12">
Latest content on <a target="_blank" href="https://dev.to/">Dev.to</a>
</h2>
<div class="grid lg:grid-cols-3 gap-6">
<ExploreItem v-for="article in articles" :article="article" />
</div>
</TwoColumnLayout>
</template>
最后,让我们创建一个可以用于404页面的空白全页布局。
<template>
<main class="container my-24 px-6 mx-auto">
<slot />
</main>
</template>
即使实现简单,只使用一个居中容器(这次使用tailwind.css),使用布局仍然很重要。
这样我们可以保持页面组件的简洁,并确保使用此布局的多个页面外观和行为一致。
<script setup>
import BlankLayout from "../layouts/BlankLayout.vue";
import PageNotFound from "../components/PageNotFound.vue";
</script>
<template>
<BlankLayout>
<PageNotFound />
</BlankLayout>
</template>
布局是减少样板代码和保持专业外观的重要工具。结合完善的文件夹结构,可以创建一个让每个人都喜欢使用的代码库。
由于文章内容篇幅有限,今天的内容就分享到这里,文章结尾,我想提醒您,文章的创作不易,如果您喜欢我的分享,请别忘了点赞和转发,让更多有需要的人看到。同时,如果您想获取更多前端技术的知识,欢迎关注我,您的支持将是我分享最大的动力。我会持续输出更多内容,敬请期待。