这是我参与更文挑战的第19天,活动详情查看:更文挑战
效果图
查看文档
vant的tabbar标签栏
俺们选这个,带自定义图标的
1. 先写骨架
<template>
<van-tabbar v-model="active" fixed route active-color=”#6689e2“>
<van-tabbar-item v-for="(item, index) in tabbars" :to="item.to" :key="index">
<span>{{ item.title }}</span>
<template #icon="props">
<img :src.sync="props.active ? item.image_active : item.image" />
</template>
</van-tabbar-item>
</van-tabbar>
</template>
2. 写js,由于是做成组件,所以需要单独抽离出来
<script lang="ts">
import { defineComponent, PropType, ref } from "vue"
// ts 定义类型并且暴露出去
export interface ITabList {
title: string // 标题
to: { name: string } // url路径
image: string // 初始图标
image_active: string // 选中图标
}
export default defineComponent({
name: "TabBar",
props: {
defaultActive: {
type: Number,
default: 0
},
tabbars: {
type: Array as PropType<ITabList[]>, // 类型断言
default: () => {
return []
}
}
},
setup(props) {
const active = ref(props.defaultActive)
return { active }
}
})
</script>
至此,tabbar就已经完成了。
让我们试验一下吧
在views
里面,创建layout.vue
<!-- layouts -->
<template>
<div class="app-container">
<div class="layout-content">
<keep-alive v-if="$route.meta.keepAlive">
<router-view></router-view>
</keep-alive>
<router-view v-else></router-view>
</div>
<div class="layout-footer" v-if="$route.meta.showTab">
<!-- 这里@change默认绑定在了van-tabbar上,参考vue的$attr -->
<TabBar
:tabbars="tabbars"
:defaultActive="defaultActive"
@change="handleChange"
/>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, reactive, toRefs } from "vue"
import TabBar, { ITabList } from "@/components/TabBar.vue"
import { useRoute } from "vue-router"
import indexPng from '@assets/tabbar/index.png'
import indexActivePng from '@assets/tabbar/index-active.png'
import etcPng from '@assets/tabbar/etc.png'
import etcActivePng from '@/assets/tabbar/etc-active.png'
import bbsPng from '@assets/tabbar/bbs.png'
import bbsActivePng from '@assets/tabbar/bbs-active.png'
import couponPng from '@assets/tabbar/coupon.png'
import couponActivePng from '@assets/tabbar/coupon-active.png'
import myPng from '@assets/tabbar/my.png'
import myActivePng from '@assets/tabbar/my-active.png'
interface ILayoutState {
tabbars: Array<ITabList>
defaultActive: number
}
export default defineComponent({
name: "layouts",
components: { TabBar },
setup() {
const route = useRoute();
const state: ILayoutState = reactive({
tabbars: [
{ title: "首页", to: { name: "Index" }, image: indexPng, image_active: indexActivePng },
{ title: "记账", to: { name: "Etc" }, image: etcPng, image_active: etcActivePng },
{ title: "论坛", to: { name: "Todo" }, image: bbsPng, image_active: bbsActivePng },
{ title: "优惠", to: { name: "Coupon" },image: couponPng,image_active: couponActivePng },
{ title: "我的", to: { name: "My" }, image: myPng, image_active: myActivePng }
],
defaultActive: computed(() => {
return state.tabbars.findIndex((item: ITabList) => {
return item.to.name === route.name
})
})
})
const handleChange = (v: number) => {
console.log("tab value:", v)
}
return {
...toRefs(state),
handleChange
}
}
});
</script>
这里有一个坑,不知道为什么,我直接写'@/assets/tabbar/index.png',这种格式会报错。。所以就只能用import * from ** 的方式来实现了。有小伙伴有答案麻烦告诉我一下,谢谢
ok,功能实现了,那么就该去定义router和创建文件了
- 在
views
里面,创建tabbar
文件夹,并且创建五个对应tabbar的文件
- 然后,去
router
文件夹下面的router.config.js
里面写对应的路由
import { RouteRecordRaw } from "vue-router";
export const constantRouterMap: Array<RouteRecordRaw> = [
{
path: "/",
name: "/",
component: () => import("@/views/layout.vue"),
redirect: "/Index",
meta: { title: "首页", keepAlive: false },
children: [
{ path: "/index", name: "Index", component: () => import("@/views/tabbar/index.vue"), meta: { title: "首页", keepAlive: false, showTab: true } },
{ path: "/etc", name: "Etc", component: () => import("@/views/tabbar/etc.vue"), meta: { title: "记账", keepAlive: false, showTab: true } },
{ path: "/todo", name: "Todo", component: () => import("@/views/tabbar/todo.vue"), meta: { title: "论坛", keepAlive: false, showTab: true } },
{ path: "/coupon", name: "Coupon", component: () => import("@/views/tabbar/coupon.vue"), meta: { title: "优惠", keepAlive: false, showTab: true } },
{ path: "/my", name: "My", component: () => import("@/views/tabbar/my.vue"), meta: { title: "我的", keepAlive: false, showTab: true } }
]
}
]
酱紫,一个完整的tabbar路由封装就实现啦!!!
搞掂收工,有不懂的尽管问,我有空就会回复的啦
大佬们,感兴趣可以关注我公众号鸭,现在还是个位数呢,委屈屈...
人懒,不想配图,望能帮到大家
公众号:
小何成长
,佛系更文,都是自己曾经踩过的坑或者是学到的东西有兴趣的小伙伴欢迎关注我哦,我是:
何小玍。
大家一起进步鸭
记叙文:
技术文
乱七八糟系列
vue系列
- 【Vue版本 - 前端实践系列之九】登录注册界面千篇一律?教你做个炫酷的!
- vue3的setup和Ref 语法
- vue3的provide和inject
- [项目篇]vue3 + vite + vant + typescript - 第一天
- [项目篇]vue3+ts 封装request请求,storage缓存,config请求信息抽离 - 第二天
typescript系列
- 手摸手一起学习Typescript第一天,数据类型和vscode的搭配typescript
- 手摸手一起学习Typescript第二天,interface接口和readonly属性
- 手摸手一起学习Typescript第三天 - 函数Function
- 手摸手一起学习Typescript第四天 - 类型推论,联合类型 和 类型断言
- 手摸手一起学习Typescript第五天 - Class 类 / 类与接口
- 手摸手一起学习Typescript第六天 - 泛型 Generics / 泛型约束 / 泛型与类和接口
- 手摸手一起学习Typescript第七天 - 类型别名 和 交叉类型
- 手摸手一起学习Typescript第八天 - 声明文件 、内置类型