移动端页面的两大骨架
一个典型移动端 App 的页面结构:
<nav> NavBar 顶部导航
<main> 页面主内容区
<footer> Tabbar 底部标签栏
Vant 用 van-nav-bar 和 van-tabbar 分别实现。
NavBar 顶部导航
<template>
<van-nav-bar
title="文章详情"
left-text="返回"
left-arrow
@click-left="goBack"
/>
<van-nav-bar title="设置">
<template #right>
<van-icon name="search" size="20" @click="onSearch" />
</template>
</van-nav-bar>
<van-nav-bar
title="标题"
:border="false"
fixed
placeholder
safe-area-inset-top
/>
</template>
<script setup>
import { useRouter } from "vue-router";
const router = useRouter();
const goBack = () => {
if (window.history.length > 1) {
router.back();
} else {
router.push("/");
}
};
</script>
- left-arrow:显示返回箭头
- fixed + placeholder:固定在顶部并占位(防止内容被遮挡)
- safe-area-inset-top:适配 iPhone 刘海屏
Tabbar 底部导航
<template>
<van-tabbar v-model="active" route safe-area-inset-bottom>
<van-tabbar-item icon="home-o" to="/">首页</van-tabbar-item>
<van-tabbar-item icon="orders-o" to="/orders">订单</van-tabbar-item>
<van-tabbar-item icon="user-o" to="/profile">我的</van-tabbar-item>
</van-tabbar>
</template>
<script setup>
import { ref } from "vue";
const active = ref(0);
</script>
- v-model:绑定当前激活的 tab 索引
- route:启用路由模式,点击自动跳转 Vue Router
- safe-area-inset-bottom:适配 iPhone 底部安全区
实战:完整的 App 骨架
<template>
<div class="app-container">
<van-nav-bar
v-if="showNav"
:title="navTitle"
left-arrow
@click-left="onBack"
fixed
placeholder
safe-area-inset-top
>
<template #right v-if="showSearch">
<van-icon name="search" size="20" @click="$router.push('/search')" />
</template>
</van-nav-bar>
<main class="page-content">
<router-view />
</main>
<van-tabbar v-model="active" route safe-area-inset-bottom v-if="showTab">
<van-tabbar-item icon="home-o" to="/">首页</van-tabbar-item>
<van-tabbar-item icon="apps-o" to="/categories">分类</van-tabbar-item>
<van-tabbar-item icon="cart-o" to="/cart">购物车
<template #badge>
<van-badge :content="cartCount" />
</template>
</van-tabbar-item>
<van-tabbar-item icon="user-o" to="/profile">我的</van-tabbar-item>
</van-tabbar>
</div>
</template>
<script setup>
import { ref, computed } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
const active = ref(0);
const cartCount = ref(3);
const showNav = computed(() => !route.meta.hideNav);
const showTab = computed(() => !route.meta.hideTab);
const showSearch = computed(() => route.meta.showSearch);
const navTitle = computed(() => route.meta.title || "");
const onBack = () => {
if (history.length > 1) history.back();
else location.href = "/";
};
</script>
<style>
.app-container {
min-height: 100vh;
display: flex;
flex-direction: column;
}
.page-content {
flex: 1;
padding-bottom: env(safe-area-inset-bottom);
}
</style>
路由 meta 配置示例
// router/index.js
const routes = [
{
path: "/",
component: Home,
meta: { title: "首页", showSearch: true },
},
{
path: "/login",
component: Login,
meta: { hideNav: true, hideTab: true },
},
{
path: "/article/:id",
component: ArticleDetail,
meta: { title: "文章详情" },
},
];
通过 route.meta 来控制每个页面的 NavBar 和 Tabbar 显示,非常灵活。