前言
本章只介绍添加 tabbar 页面。
新建 tab 页
在 views 目录下创建几个 tab 页:
添加路由
tabbar
在 router 目录创建 tabbar.js:
内容如下:
const Home = () => import(/* webpackChunkName: "index" */ "@/views/index/index.vue");
const Category = () => import(/* webpackChunkName: "index" */ "@/views/category/category.vue");
const Cart = () => import(/* webpackChunkName: "index" */ "@/views/cart/cart.vue");
const User = () => import(/* webpackChunkName: "index" */ "@/views/user/user.vue");
const tabbar = [
{
path: "/",
name: "home",
component: Home,
meta: {
title: "精选",
tabbar: true,
icon: "home-o",
tabName: "精选",
index: 1
}
},
{
name: "category",
path: "/category",
component: Category,
meta: {
title: "分类",
tabbar: true,
icon: "bag-o",
tabName: "分类",
index: 2
}
},
{
name: "cart",
path: "/cart",
component: Cart,
meta: {
title: "购物车",
tabbar: true,
icon: "cart-o",
tabName: "购物车",
index: 3
}
},
{
name: "user",
path: "/user",
component: User,
meta: {
title: "个人中心",
tabbar: true,
icon: "user-o",
tabName: "我",
index: 4
}
}
];
export default tabbar;
其中:
webpackChunkName:会将名字相同的打包到一起
tabbar:路由数组,其中1、name:路由的名字 2、path:路由的 history 路径,即 url 3、component:组件,使用的模板页面 4、meta:自定义数据,这里 title 后续用来修改浏览器标题,tabbar,用来区分是否是 tabbar 页,icon 和 tabName 和 index 用来辅助展示 tabbar
index
修改 router 下的 index.js,为路由的入口配置,引入 tabbar.js,详细内容如下:
import Vue from "vue";
import VueRouter from "vue-router";
import Tabbar from "./tabbar.js";
Vue.use(VueRouter);
const routes = [
...Tabbar
];
/**如果路径不存在,就按照/ + name 驼峰转斜杠,来填充 */
routes.forEach(route => {
route.path = route.path || "/" + (route.name.replace(/([A-Z])/g, "/$1").toLowerCase() || "");
});
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
/**路由进入前回调 */
router.beforeEach((to, from, next) => {
// 修改浏览器页面标题
const title = to.meta && to.meta.title;
if (title) {
document.title = title;
}
next();
});
export default router;
修改容器页面
修改 public 目录下的 index.html,修改 viewport,如果没有就添加:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no,viewport-fit=cover">
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no,viewport-fit=cover">
<link rel="icon" href="<%= BASE_URL %>favicon.png">
<title>微商城</title>
</head>
<body>
<noscript>
<strong>We're sorry but wxshop doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
其中 width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no
是初始化页面缩放大小,并禁止用户对页面缩放,后面那个 viewport-fit=cover
是辅助 ios 安全距离使用的:
修改入口 App
这才是真正的添加 tabbar,修改 App.vue:
<template>
<div id="app">
<!-- 内容 -->
<transition :name="transitionName" mode="out-in" >
<!-- keep-alive 标签会缓存页面,缓存所有模板名称以KeepAlive结尾的页面或组件 -->
<keep-alive :include="/KeepAlive$/">
<router-view />
</keep-alive>
</transition>
<!-- tabbar -->
<van-tabbar route safe-area-inset-bottom>
<van-tabbar-item
v-for="(tab, index) in tabbar"
:key="index"
:to="tab.path"
:icon="tab.meta.icon"
>{{tab.meta.tabName}}</van-tabbar-item>
</van-tabbar>
</div>
</template>
<script>
import { Tabbar, TabbarItem } from "vant";
import TabbarRoute from "@/router/tabbar.js";
export default {
name: "App",
components: {
[Tabbar.name]: Tabbar,
[TabbarItem.name]: TabbarItem
},
data() {
return {
transitionName: "fade",
tabbar: TabbarRoute
};
},
watch: {
$route(to, from) {
if (from.name) {
/**不是初始页面 */
if (to.meta.tabbar) {
const toDepth = to.meta.index;
const fromDepth = from.meta.index;
this.transitionName =
toDepth < fromDepth ? "slide-right" : "slide-left";
} else {
const toDepth = to.path.split("/").length;
const fromDepth = from.path.split("/").length;
this.transitionName =
toDepth < fromDepth ? "slide-right" : "slide-left";
}
} else {
/**初始页面,from.name一定没有值 */
this.transitionName = "fade";
}
}
}
};
</script>
<style lang="scss">
html,
body,
#app {
background: #ededed;
height: 100%;
margin: 0;
padding: 0;
}
html,
body,
div,
p,
ul,
li,
img,
h1,
h2,
h3,
h4,
h5,
h6 {
box-sizing: border-box;
}
img {
max-width: 100%;
display: inline-block;
}
</style>
<style>
/* 切换动画 */
.slide-right-leave-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-left-enter-active {
transition: all 0.3s;
}
.slide-right-enter {
opacity: 1;
transform: translateX(-100%);
}
.slide-right-leave-to {
opacity: 0;
transform: translateX(100%);
}
.slide-left-enter {
opacity: 1;
transform: translateX(100%);
}
.slide-left-leave-to {
opacity: 0;
transform: translateX(-100%);
}
.fade-leave-active,
.fade-enter-active {
transition: opacity 0.2s;
}
.fade-enter,.fade-leave-to{
opacity: 0;
}
</style>
其中:
1、keep-alive 缓存页面作用,一个商品列表,滑动三页,打开一个商品详情,点击返回,能否回到第三页浏览的位置?,如果列表页面加了缓存,会回到原来的位置,否则就会重新加载页面。
3、tabbar 使用 vant 的组件,route 属性表示根据路由改变 tabbar,safe-area-inset-bottom 属性表示开启 ios 的安全距离(需要viewport-fit=cover
才起作用)。
4、transition 动画,用来使页面产生过度效果。
5、watch 监听路由变化,用来确定使用的过度动画,这里设计了三种动画,fade、slide-right、slide-left。
6、添加动画样式
测试
在管理后台点击运行启动:
点击切换是否有特效,我这边是有的,测试成功。
调整 tabbar
将 App.vue 中 tabbar 改为组件,在 components 文件夹下新建 tabbar.vue 组件,内容如下:
代码:
<van-tabbar route safe-area-inset-bottom>
<van-tabbar-item
v-for="(tab, index) in tabbar"
:key="index"
:to="tab.path"
:icon="tab.meta.icon"
>{{tab.meta.tabName}}</van-tabbar-item>
</van-tabbar>
</template>
<script>
import { Tabbar, TabbarItem } from "vant";
import TabbarRoute from "@/router/tabbar.js";
export default {
name: "tabbar",
components: {
[Tabbar.name]: Tabbar,
[TabbarItem.name]: TabbarItem
},
data(){
return {
tabbar: TabbarRoute
}
}
};
</script>
修改 tabbar 路由:
代码:
const Home = () => import(/* webpackChunkName: "index" */ "@/views/index/index.vue");
const Category = () => import(/* webpackChunkName: "index" */ "@/views/category/category.vue");
const Cart = () => import(/* webpackChunkName: "index" */ "@/views/cart/cart.vue");
const User = () => import(/* webpackChunkName: "index" */ "@/views/user/user.vue");
const Tabbar = () => import(/* webpackChunkName: "index" */ "@/components/tabbar.vue");
const tabbar = [
{
path: "/",
name: "home",
components: {
default: Home,
tabbar: Tabbar
},
meta: {
title: "精选",
tabbar: true,
icon: "home-o",
tabName: "精选",
index: 1
}
},
{
name: "category",
path: "/category",
components: {
default: Category,
tabbar: Tabbar
},
meta: {
title: "分类",
tabbar: true,
icon: "bag-o",
tabName: "分类",
index: 2
}
},
{
name: "cart",
path: "/cart",
components: {
default: Cart,
tabbar: Tabbar
},
meta: {
title: "购物车",
tabbar: true,
icon: "cart-o",
tabName: "购物车",
index: 3
}
},
{
name: "user",
path: "/user",
components: {
default: User,
tabbar: Tabbar
},
meta: {
title: "个人中心",
tabbar: true,
icon: "user-o",
tabName: "我",
index: 4
}
}
];
export default tabbar;
修改 App.vue:
代码:
<template>
<div id="app">
<!-- 内容 -->
<transition :name="transitionName" mode="out-in">
<!-- keep-alive 标签会缓存页面,缓存所有模板名称以KeepAlive结尾的页面或组件 -->
<keep-alive :include="/KeepAlive$/">
<router-view />
</keep-alive>
</transition>
<!-- tabbar -->
<keep-alive>
<router-view name="tabbar" />
</keep-alive>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
transitionName: "fade"
};
},
watch: {
$route(to, from) {
if (from.name) {
/**不是初始页面 */
if (to.meta.tabbar) {
const toDepth = to.meta.index;
const fromDepth = from.meta.index;
this.transitionName =
toDepth < fromDepth ? "slide-right" : "slide-left";
} else {
const toDepth = to.path.split("/").length;
const fromDepth = from.path.split("/").length;
this.transitionName =
toDepth < fromDepth ? "slide-right" : "slide-left";
}
} else {
/**初始页面,from.name一定没有值 */
this.transitionName = "fade";
}
}
}
};
</script>
<style lang="scss">
html,
body,
#app {
background: #ededed;
height: 100%;
margin: 0;
padding: 0;
position: relative;
}
html,
body,
div,
p,
ul,
li,
img,
h1,
h2,
h3,
h4,
h5,
h6 {
box-sizing: border-box;
}
img {
max-width: 100%;
display: inline-block;
}
.line1 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
word-break: break-all;
}
.line2 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.line3 {
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
</style>
<style>
/* 切换动画 */
.slide-right-leave-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-left-enter-active {
transition: all 0.3s;
}
.slide-right-enter {
opacity: 1;
transform: translateX(-100%);
}
.slide-right-leave-to {
opacity: 0;
transform: translateX(100%);
}
.slide-left-enter {
opacity: 1;
transform: translateX(100%);
}
.slide-left-leave-to {
opacity: 0;
transform: translateX(-100%);
}
.fade-leave-active,
.fade-enter-active {
transition: opacity 0.2s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>
router-view
组件指定渲染的路由组件名称,详细说明查看官网文档。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。