目标: 做一个导航tabbar
一. 分析我们的目标是做一个导航tabbar, 要求
这个导航不仅可以在一个页面使用, 可以在多个页面通用
每个页面的样式可能不一样
每个页面的图标, 文字可能不一样
每个页面导航的个数可能不一样
要想实现上面的情况, 需要进行功能拆解:
提炼出一个通用的tabBar, 然后在里面定义插槽, 根据需要放入tabBarItem,
tabBarItem里面包含图片, 文字. 图片和文字也是插槽, 不同的tabBarItem显示的图片的文字都有可能不同.
tabBarItem的数据结构需要定义为一个json, 指定跳转的url
二. 框架实现 1. 通常我们如何实现? 第一步: 在App.vue中定义一段HTML, 外层div的id是tabBar, 内层div的class标签属性是tabBarItem. <template> <div> <div> <div>首页</div> <div>分类</div> <div>购物车</div> <div>我的</div> </div> </div> </template> 第二步: 定义body样式.通常body样式, 我们将其单独定义到main.css文件中. 放在assets目录下
body { margin: 0px; padding: 0px; }定义好了main.css文件, 需要将其引入到App.vue文件中
<style> @import "./assets/main.css"; </style>引入css文件样式使用的是@import '文件路径', 而引入js文件使用的是import '文件路径'
第三步: 定义tabBar样式tabBar采用的是Flex弹性布局的布局方式.
#tabBar { display: flex; } .tabBarItem { flex: 1; text-align: center; }上面这段代码就指定了tabBar采用的布局方式. 它会根据子元素的个数进行弹性布局. 在子元素中我们设置每个元素的flex: 1
表示的是在空间可用的情况下, 平均分配空间.
这里面除了有布局样式,还有底部对齐, 导航的阴影等等.
总结: 这样的导航不通用, 如果我们要复用, 需要拷贝html内容, 还要拷贝css样式. 我们可以把公共部分提成一个组件
2. 抽象tabBarItem组件 第一步: 在components中新建一个组件tabBarItem这个提取比较简单, 就是将我们刚刚在App.vue中的功能提取出一个单独的组件
<template> <div> <div>首页</div> <div>分类</div> <div>购物车</div> <div>我的</div> </div> </template> <script> export default { name: "tabBarItem" } </script> <style scoped> #tabBar { display: flex; background-color: #e6e6e6; position: fixed; left: 0; right: 0; bottom: 0; box-shadow: 0 -3px 1px darkgrey; } .tabBarItem { flex: 1; text-align: center; } </style>然后, 在App.vue中引入组件
<script> import TabBar from "./components/TabBar" export default { name: 'App', components: { TabBar } } </script>vue里面, 可以使用组件的简称调用组件, 如下所示:
<div> <tab-bar></tab-bar> </div>这样, tabBarItem的可复用性就更强了.
3. 完善tabBarItem组件我们知道tabBar除了有图片, 还有文字. 当我们鼠标点击的时候还有对应的图片或者蚊子样式的变化.
下面我们来实现, 改变图片和文字.
第一步: 在tabBarItem中放两张图片, 一张是未点击的, 另一张是点击后的图片. 图片自备, 什么图都可以
如上代码: 比之前多了一个slot, 用来存放第二张图片的.
在调用的地方传两张图片过来
这里就传了两张图片, 并指定每张图片的插槽位置
然后我们来看看效果:
效果出来了,达到预期. 但我们希望:鼠标不点击,显示图一; 鼠标点击, 显示图二.
这个容易实现, 使用一个isActive变量即可
修改TabBarItem组件
在组件脚本中定义一个变量isActive, 然后对插槽使用v-if即可实现效果. 注意v-if和v-else的写法.
这里我们有一个约定,通常不在插槽的里面写v-if或者v-else, 因为这部分内容后面会被替换掉. 所以, 在外层包一个div