🎉🎉🎉欢迎来到我的博客,我是一名自学了2年半前端的大一学生,熟悉的技术是JavaScript与Vue.目前正在往全栈方向前进, 如果我的博客给您带来了帮助欢迎您关注我,我将会持续不断的更新文章!!!🙏🙏🙏
@[toc]
1. 实现Tab-Bar思路
- 下方单独的
Tab-Bar
组件如何封装?- 自定义
Tab-Bar
组件,在APP中使用 - 让
Tab-Bar
位置在底部,并设置你需要的样式
- 自定义
Tab-Bar
中显示的内容由外部决定- 定义插槽
- flex布局平分
Tab-Bar
- 自定义
Tab-Bar-Item
,可以传入图片和文字- 定义
Tab-Bar-Item
,并定义两个插槽:图片和文字 - 给插槽外层包装
div
,设置样式 - 填充插槽,实现底部
Tab-Bar
的效果
- 定义
- 传入高亮图片
- 定义另一个插槽,插入
active-icon
的数据 - 定义一个变量
isActicve
,通过v-show
来决定是否显示对应的icon
- 定义另一个插槽,插入
Tab-Bar-Item
绑定路由数据- 安装路由:
npm install vue-router --save
- 在
router/index.js
配置路由信息,并创建对应的组件 main.js
中注册router
App.vue
中使用router-link
和router-view
- 安装路由:
- 点击item跳转到对应的路由,并且动态决定
isActive
- 监听
item
的点击,通过this.$router.replace()
替换路由路径 - 通过
this.$route.path.indexOf(this.link)!==-1
来判断是否使active
- 监听
- 动态计算active样式
- 封装新的计算属性:
this.isActive?{'color': 'red'}:{}
- 封装新的计算属性:
2. 代码实现
使用vue init webpack 02-vue-router-tabbar-v1
新建一个项目工程(使用vuecli2
)。
在文件夹assest下新建css/base.css,用于初始化css
base.css
body {
padding: 0;
margin: 0;
}
修改App.vue,添加初步样式
<template>
<div id="app">
<div id="tar-bar">
<div class="tar-bar-item">首页</div>
<div class="tar-bar-item">分类</div>
<div class="tar-bar-item">购物车</div>
<div class="tar-bar-item">我的</div>
</div>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
/* style中引用使用@import */
@import url('./assets/css/base.css');
#tar-bar {
display: flex;
background-color: #f6f6f6;
position: fixed;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 -1px 1px rgba(100, 100, 100, .2);
}
.tar-bar-item {
flex: auto;
text-align: center;
height: 49px;
font-size: 20px;
}
</style>
使用npm run dev,查看网页效果
![](https://img-blog.csdnimg.cn/img_convert/d2bcac64e250c41047295ecc0ec2a609.png)
思考:如果每次都要复用tabbar,那每次都需要复制粘贴,应该要把tabbar抽离出来,vue就是组件化思想。
将tabbar抽离成组件
在components下新建tabbar文件夹,新建
TarBar.vue
和TabBarItem.vue
,TabBarItem
组件是在组件TarBar
中抽取出来的,可以传入图片和文字(比如首页),所有需要使用插槽<slot>
代替。TarBar.vue
<template>
<div id="tab-bar">
<!-- 插槽代替tabbaritem -->
<slot></slot>
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: 'TabBar'
}
</script>
<style scoped>
#tab-bar {
display: flex;
background-color: #f6f6f6;
position: fixed;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 -1px 1px rgba(100, 100, 100, .2);
}
</style>
TabBar弄一个slot插槽用于插入TabBarItem组件(可能插入多个).
TabBarItem.vue
<template>
<div class="tab-bar-item">
<!-- item-icon表示图片插槽 item-text表示文字插槽,例如首页 -->
<slot name="item-icon"></slot>
<slot name="item-text"></slot>
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: 'TabBarItem'
}
</script>
<style scoped>
.tab-bar-item {
flex: auto;
text-align: center;
height: 49px;
font-size: 14px;
}
.tab-bar-item img {
height: 24px;
width: 24px;
margin-top: 3px;
vertical-align: middle;
margin-bottom: 2px;
}
</style>
TabBarItem组件中插入2个插槽一个用于插入图片一个用于插入文字。
MainTabBar.vue
<template>
<div class="main-tab-bar">
<TabBar>
<TabBarItem path="/home" activeColor="blue">
<img slot="item-icon" src="~assets/img/tabbar/home.png" alt="" srcset="">
<template v-slot:item-text>
<div>首页</div>
</template>
</TabBarItem>
<TabBarItem path="/categories">
<template #item-icon>
<img src="~assets/img/tabbar/categories.png" alt="" srcset="">
</template>
<template #item-text>
<div>分类</div>
</template>
</TabBarItem>
<TabBarItem path="/shop">
<template #item-icon>
<img src="~assets/img/tabbar/shopcart.png" alt="" srcset="">
</template>
<template #item-text>
<div>购物车</div>
</template>
</TabBarItem>
<TabBarItem path="/me">
<template #item-icon>
<img src="~assets/img/tabbar/profile.png" alt="" srcset="">
</template>
<template #item-text>
<div>我的</div>
</template>
</TabBarItem>
</TabBar>
</div>
</template>
<script type="text/ecmascript-6">
import TabBar from "@/components/tabbar/TabBar"
import TabBarItem from "@/components/tabbar/TabBarItem"
export default {
name: "MainTabBar",
components: {
TabBar,
TabBarItem
}
}
</script>
<style scoped>
</style>
在MainTabBar组件中加入另外2个组件。
注意此处使用
~assets
和@/components
是使用了别名配置,详情请看3.别名配置
最后在app.vue中导入MainTabBar组件。
<template>
<div id="app">
<MainTabBar></MainTabBar>
</div>
</template>
<script>
import MainTabBar from '@/components/MainTabBar'
export default {
name: 'App',
components: {
MainTabBar
}
}
</script>
<style>
/* style中引用使用@import */
@import url('./assets/css/base.css');
</style>
效果如图所示,将组件进行了分离重组,只要修改MainTabBar组件就可以修改图片和文字描述,可以复用。
如何实现点击首页首页字体变红图片变红色
这里需要用到路由的
active-class
。思路:引用2张图片,一张是正常颜色一张是红色,使用
v-if
和v-else
来处理是否变色,在路由处于活跃状态的时候,变红色。引入路由使用路由就不细说了,这里仅贴上tabbar的修改代码。
TabBarItem.vue组件
<template> <div class="tab-bar-item" :style="activeStyle" @click="itemClick"> <!-- item-icon表示图片插槽 item-text表示文字插槽,例如首页 --> <div v-if="!isActive"> <slot name="item-icon"></slot> </div> <div v-else> <slot name="item-icon-active"></slot> </div> <div :class="{active:isActive}"> <slot name="item-text"></slot> </div> </div> </template> <script type="text/ecmascript-6"> export default { name: 'TabBarItem', props:{ path:String, activeColor:{ type:String, default:'red' } }, computed: { isActive(){ return this.$route.path.indexOf(this.path) !== -1 }, activeStyle(){ return this.isActive ? {color: this.activeColor} : {} } }, methods: { itemClick(){ this.$router.push(this.path) } } } </script> <style scoped> .tab-bar-item { flex: auto; text-align: center; height: 49px; font-size: 14px; } .tab-bar-item img { height: 24px; width: 24px; margin-top: 3px; vertical-align: middle; margin-bottom: 2px; } </style>
- 使用
props
获取传递的值,这里传递是激活颜色,默认是红色 - 设置计算属性
isActive
和activeStyle
,分别表示激活状态和激活的样式 - 定义
itemClick()
方法用于获取点击事件,点击后使用代码实现路由跳转,这里使用默认的hash模式 使用
v-if
和v-else
来进行条件判断MainTabBar.vue组件
<TabBarItem path="/home"> <img slot="item-icon" src="~assets/img/tabbar/home.png" alt="" srcset=""> <img slot="item-icon-active" src="~assets/img/tabbar/home_active.png" alt="" srcset=""> <template v-slot:item-text> <div>首页</div> </template> </TabBarItem>
添加激活状态的图片与未激活的图片并列。
配置路由信息,参考之前的代码
```js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const routes = [
{
path: '/',
redirect: '/home'//缺省时候重定向到/home
},
{
path: '/home',
component: () => import ('../views/home/Home.vue')
},
{
path: '/categories',
component: () => import ('../views/categories/Categories.vue')
},
{
path: '/shop',
component: () => import ('../views/shop/Shop.vue')
},
{
path: '/profile',
component: () => import ('../views/profile/Profile.vue')
},
]
export default new Router({
routes,
// linkActiveClass:"active"
})
![](https://img-blog.csdnimg.cn/img_convert/ae74ed82b3195905237cf13507385c9e.png)
5. 修改main.js和App.vue
```js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render: h => h(App)
})
<template>
<div id="app">
<router-view></router-view>
<MainTabBar></MainTabBar>
</div>
</template>
<script>
import MainTabBar from '@/components/MainTabBar'
export default {
name: 'App',
components: {
MainTabBar
}
}
</script>
<style>
/* style中引用使用@import */
@import url('./assets/css/base.css');
</style>
3. 别名配置
经常的我们向引入图片文件等资源的时候使用相对路径,诸如../assets/xxx
这样的使用../
获取上一层,如果有多个上层就需要../../xxx
等等这样不利于维护代码。此时就需要一个能获取到指定目录的资源的就好了。
配置
在webpack.base.config
中配置使用别名,找到resolve:{}模块,增加配置信息
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
'assets': resolve('src/assets'),
'components': resolve('src/components'),
'views': resolve('scr/views')
}
},
这里@
指定目录是src
,例如@/components
表示src/components
目录,assets
表示src/assets
前缀,如果是assets/img
就表示src/assets/img
目录。
Hi👋,这里是瑞雨溪一个喜欢JavaScript和Vue的大学生,如果我的文章给你带来的帮助,欢迎您关注我,我会持续不断的更新更多优质文章.你的关注就是我的动力!!!🎉🎉🎉