其实封装一个自定义的底部切换栏组件很简单,因为功能十分单一。封装复用的、功能多样的组件才是一件难事!还有写文章也挺不容易的(。•ˇ‸ˇ•。)
为什么要封装:这种废话就不多说了,上一篇关于封装轮播图组件的文章已经有浅谈过。而且作为一名积极上进的前端开发,多点练习封装组件真的很有必要。
为什么不使用组件库:组件库用起来确实很方便,但是我还是想自己封装一遍,理清其中的逻辑思路。而且Tabbar这种底部切换栏,其实是很简单的效果,实现起来不难也很容易理解。
来了啵,下面进入正题!
Tabbar效果展示
点击不同的图标,切换到各自对应的页面,并显示活跃状态。
如何实现
HTML结构
一个ul列表,包含4个li子元素(当然也可以用普通的div盒子包裹4个div子元素)
每个li切换项,包含一张图片和文字
在data中定义一个切换项数组routerList,每一个数组项顺序对应每一个切换项
数组项是一个对象,包含{路径、选中状态的图片、未选中状态的图片、标题}
如何改变 选中和未选中 的状态
遍历生成结构时,img标签的图片路径为一个三元表达式,判断当前路由是否以自己数据项的路径开头,true则赋值选中状态是图片,否则赋值未选中状态的图片
<!-- HTML结构 -->
<div class="tabbar">
<ul>
<li
v-for="(item, index) in routerList"
:key="index"
@click="changePath(item.path)"
>
<img
:src="$route.path.startsWith(item.path) ? item.selected : item.active"
alt=""
/>
<span :class="$route.path.startsWith(item.path) ? 'active' : ''">
{{item.title}}
</span>
</li>
</ul>
</div>
CSS布局样式
flex 弹性盒布局是最方便简单的
- ul列表 :弹性布局, 固定宽高,垂直居中
- li子元素 :垂直方向开启弹性布局,均分ul列表的宽度,水平居中
- 图片:固定宽高
JS动态效果
为每个li切换项绑定click回调,参数是每个li的路径 定义回调函数,判断接收的路径是否与当前路由路径相同,不相同才切换页面
methods: {
changePath(path) {
// 跳转路径 先判断点击的是否同一个,相同则return
if (path == this.$route.path) return;
else this.$router.replace(path);
},
},
完整代码
<template>
<!-- HTML结构 -->
<div class="tabbar">
<ul>
<li
v-for="(item, index) in routerList"
:key="index"
@click="changePath(item.path)"
>
<img
:src="$route.path.startsWith(item.path) ? item.selected : item.active"
alt=""
/>
<span :class="$route.path.startsWith(item.path) ? 'active' : ''">
{{ item.title }}
</span>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "Tabbar",
// 遍历的数据
data() {
return {
routerList: [
{
title: "首页",
active: "./images/home.png", //未选中
selected: "./images/home-select.png", //选中
path: "/home",
},
{
title: "分类",
active: "./images/list.png", //当然图片都可以自定义
selected: "./images/list-select.png",
path: "/category",
},
{
title: "购物车", //标题也是
active: "./images/cart.png",
selected: "./images/cart-select.png",
path: "/cart",
},
{
title: "我的",
active: "./images/my.png",
selected: "./images/my-select.png",
path: "/my",
},
],
};
},
methods: {
changePath(path) {
// 跳转路径 先判断点击的是否同一个,相同则return
if (path == this.$route.path) return;
else this.$router.replace(path);
},
},
};
</script>
<style scoped lang="scss">
.tabbar { // 使用了scss 预处理器
width: 100%;
height: 1.4rem;
background-color: white;
ul {
display: flex;
justify-content: space-around;
width: 100%;
height: 100%;
li {
flex: 1;
display: flex;
flex-direction: column;
font-size: 0.4267rem;
align-items: center;
justify-content: center;
img {
width: 0.8267rem;
height: 0.8267rem;
}
}
}
}
</style>
总结
封装一个自定义组件是不是真的挺简单的?
确实!不过这只是因为我们封装的是一个底部切换栏,功能十分单一。封装复用的、功能多样的组件才是一件难事呢!
写文章也很难!虽然看起来只是很简单的内容,但是我也花了两个多小时。不简单呐.... 所以如果你看到这里了,我真的会谢!!!