使用 Vue 制作 tabbar
- Demo地址 : https://github.com/lpzzzz/vue-tabbar
1. 创建项目
-
vue-cli2.0使用 vue init webpack tabbar 命令创建项目。
vue init webpack tabbar
- 在style中引用资源需要使用 @import 进行引用;
2. 删除项目中多余的默认组件以及样式
3. 编写简单的基础界面
- 编写简单的界面启动测试。
1. npm install
2. npm run dev
3.1 清除页面的默认样式
- 在assets文件夹中创建img 和 css等静态资源文件夹。
- 清除页面默认样式
body {
margin: 0;
padding: 0;
}
- 在App.vue中引用样式
@import "./assets/css/base.css";
- 编写基本的结构代码 :快捷方法=> #tabbar>div.tabbar-item*4
<div id="tabbar">
<div class="tabbar-item">首页</div>
<div class="tabbar-item">分类</div>
<div class="tabbar-item">购物车</div>
<div class="tabbar-item">我的</div>
</div>
- 编写结构简单样式
#tabbar {
/*文字水平分布*/
display: flex;
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 49px;
background-color: #f7f7f7;
/*设置阴影 box-shadow: x轴偏移(正向右偏移) y轴偏移(正值向下偏移) 阴影高度 颜色值 */
box-shadow: 0 -3px 5px rgba(100, 100, 100, .1);
}
.tabbar-item {
/*每一项均等分*/
flex: 1;
text-align: center;
}
- 以上代码没有较强的复用性。
3.2 封装(抽取)组件
3.2.1 抽取App中的Tabbar
- 将Tabbar代码块内的代码抽取为一个新的组件Tabbar.vue
- 在App.vue中 import Tabbar from “./components/tabbar/Tabbar”
- 在 components中 注册组件
<div id="tabbar">
<div class="tabbar-item">
<img src="../../assets/img/tabbar/home.svg" alt="">
<div>首页</div>
</div>
<div class="tabbar-item">
<img src="../../assets/img/tabbar/category.svg" alt="">
<div>分类</div>
</div>
<div class="tabbar-item">
<img src="../../assets/img/tabbar/shopcart.svg" alt="">
<div>购物车</div>
</div>
<div class="tabbar-item">
<img src="../../assets/img/tabbar/profile.svg" alt="">
<div>我的</div>
</div>
</div>
3.2.2 抽取 Tabbar组件中的Tabbar-item
- 抽取Tabbar中的大量代码,使用slot插槽进行替换。
<template>
<div id="tabbar">
<slot> </slot>
</div>
</template>
<script>
export default {
name: "tabbar"
}
</script>
<style scoped>
#tabbar {
/*文字水平分布*/
display: flex;
position: fixed;
left: 0;
right: 0;
bottom: 0;
height: 49px;
background-color: #f7f7f7;
/*设置阴影 box-shadow: x轴偏移(正向右偏移) y轴偏移(正值向下偏移) 阴影高度 颜色值 */
box-shadow: 0 -3px 5px rgba(100, 100, 100, .1);
}
</style>
3.2.3 将Tabbar-item中的部分抽取出来使用具名插槽替换方便后面扩展
<template>
<div class="tabbar-item">
<!--在这里使用具名插槽在使用的时候进行替换即可-->
<slot name="slot-icon"/>
<slot name="slot-text"/>
</div>
</template>
<script>
export default {
name: "tabbar-item"
}
</script>
<style scoped>
.tabbar-item {
/*每一项均等分*/
flex: 1;
text-align: center;
vertical-align: middle;
margin-top: 3px;
font-size: 14px;
margin-bottom: 2px;
}
/*设置图标样式*/
.tabbar-item img {
height: 24px;
width: 24px;
}
</style>
3.2.4 在App中引入组件进行使用
- 在App中使用 script代码块中使用 import … 引入自定义的组件进行使用。
import Tabbar from "./components/tabbar/Tabbar"
import TabbarItem from "./components/tabbar/Tabbar-item"
- 在App中使用引入的组件如下:
<template>
<div id="app">
<Tabbar>
<tabbar-item>
<img slot="slot-icon" src="./assets/img/tabbar/home.svg" alt="">
<div slot="slot-text">首页</div>
</tabbar-item>
<tabbar-item>
<img slot="slot-icon" src="./assets/img/tabbar/category.svg" alt="">
<div slot="slot-text">分类</div>
</tabbar-item>
<tabbar-item>
<img slot="slot-icon" src="./assets/img/tabbar/shopcart.svg" alt="">
<div slot="slot-text">购物车</div>
</tabbar-item>
<tabbar-item>
<img slot="slot-icon" src="./assets/img/tabbar/profile.svg" alt="">
<div slot="slot-text">我的</div>
</tabbar-item>
</Tabbar>
</div>
</template>
<script>
import Tabbar from "./components/tabbar/Tabbar"
import TabbarItem from "./components/tabbar/Tabbar-item"
export default {
name: 'App',
components: {
// 引入组件之后需要进行注册
Tabbar,
TabbarItem
}
}
</script>
<style>
/*引入外部样式的方式样式style内需要使用 @import*/
@import "./assets/css/base.css";
</style>
3.3 给Tabbar-item传入active图片
- 新增插槽并且在插槽上加上判断根据条件进行激活显示。
<template>
<div class="tabbar-item">
<!--在这里使用具名插槽在使用的时候进行替换即可-->
<div v-if="!isActive">
<slot name="slot-icon"/>
</div>
<!--活跃状态下的图片插槽-->
<div v-else>
<slot name="slot-icon-active"/>
</div>
<!--需要使用一个div将其进行包裹起来,否则在使用的时候会将插槽的内容全部替换里面的属性样式都会被替换掉-->
<!--<slot :class="{active:isActive}" name="slot-text"/>-->
<div :class="{active:isActive}">
<slot name="slot-text"/>
</div>
</div>
</template>
<script>
export default {
name: "tabbar-item",
data() {
return {
isActive: false
}
}
}
</script>
<style scoped>
.tabbar-item {
/*每一项均等分*/
flex: 1;
text-align: center;
vertical-align: middle;
margin-top: 3px;
font-size: 14px;
margin-bottom: 2px;
}
/*设置图标样式*/
.tabbar-item img {
height: 24px;
width: 24px;
}
.active {
color: red;
}
</style>
- 注意:在使用插槽的时候填充到插槽中的内容会替换掉插槽内的所有内容,所以进行使用一个div将插槽包裹起来,在div中写一些必要的属性。像下面这样:
<!--需要使用一个div将其进行包裹起来,否则在使用的时候会将插槽的内容全部替换里面的属性样式都会被替换掉-->
<!--<slot :class="{active:isActive}" name="slot-text"/>-->
<div :class="{active:isActive}">
<slot name="slot-text"/>
</div>
3.4 Tabbar-item与路由相结合
- 每个Tabbar-item都和一个路由跳转相对应。
3.4.1 安装路由操作
- 如果在创建项目的时候没有安装路由,需要使用命令进行安装:npm install vue-router -save 。创建router文件夹。在文件夹中创建index.js文件。文件中的内容如下 :
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const Home = () => import('../views/home/Home')
const Category = () => import('../views/category/Category')
const Cart = () => import('../views/cart/Cart')
const Profile = () => import('../views/profile/Profile')
// 创建路由对象 注意这里是routes 不要写作 routers 不然切换路由时 router-view都不会显示
const routes = [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/category',
component: Category
},
{
path: '/profile',
component: Profile
},
{
path: '/cart',
component: Cart
}
]
const router = new VueRouter({
routers
})
// 导出router
export default router
3.4.2 在main.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)
})
3.4.3 创建各个组件
- 各个组件尽量不要建立到components文件夹中,该文件夹中存放的是一些公共的组件。
- 可以新建一个views或者pages存放新的每一个单一的组件。
3.4.4 在Tabbar-item组件上注册监听事件
- 监听事件上设置路由的跳转,this.$router.push(目的路径);
3.4.5 在App中传递过来跳转的路径
3.5 Tabbar-item的颜色动态控制
- 将isActive设置为计算属性,根据当前选中的路由路径判断当前选中的状态。返回一个Boolean值;
// 在TabbarItem中添加如下代码
computed: {
isActive() {
/*该条件成立的时候表示某个tabbar-item属于活跃状态*/
return this.$route.path.indexOf(this.path) !== -1
}
}
3.6 TabbarItem中文字颜色
3.6.1 思路
- 需要在props中定义一个属性。用于接收来自App中传递过来的颜色设置。设置props中的属性名称为activeColor 类型为 String 默认值为red 在TabbarItem组件中的文字上绑定上style 的计算属性。
路径判断当前选中的状态。返回一个Boolean值;
// 在TabbarItem中添加如下代码
computed: {
isActive() {
/*该条件成立的时候表示某个tabbar-item属于活跃状态*/
return this.$route.path.indexOf(this.path) !== -1
}
}
3.6 TabbarItem中文字颜色
3.6.1 思路
- 需要在props中定义一个属性。用于接收来自App中传递过来的颜色设置。设置props中的属性名称为activeColor 类型为 String 默认值为red 在TabbarItem组件中的文字上绑定上style 的计算属性。
3.7 抽取Tabbar中App中的大量代码到Main.vue组件中
<template>
<Tabbar>
<tabbar-item path="/home" activeColor="red">
<img slot="slot-icon" src="../assets/img/tabbar/home.svg" alt="">
<img slot="slot-icon-active" src="../assets/img/tabbar/home_active.svg" alt="">
<div slot="slot-text">首页</div>
</tabbar-item>
<tabbar-item path="/category" activeColor="green">
<img slot="slot-icon" src="../assets/img/tabbar/category.svg" alt="">
<img slot="slot-icon-active" src="../assets/img/tabbar/category_active.svg" alt="">
<div slot="slot-text">分类</div>
</tabbar-item>
<tabbar-item path="/cart" activeColor="blue">
<img slot="slot-icon" src="../assets/img/tabbar/shopcart.svg" alt="">
<img slot="slot-icon-active" src="../assets/img/tabbar/shopcart_active.svg" alt="">
<div slot="slot-text">购物车</div>
</tabbar-item>
<tabbar-item path="/profile">
<img slot="slot-icon" src="../assets/img/tabbar/profile.svg" alt="">
<img slot="slot-icon-active" src="../assets/img/tabbar/profile_active.svg" alt="">
<div slot="slot-text">我的</div>
</tabbar-item>
</Tabbar>
</template>
<script>
import Tabbar from "../components/tabbar/Tabbar"
import TabbarItem from "../components/tabbar/Tabbar-item"
export default {
name: "main-tabbar",
components: {
// 引入组件之后需要进行刚注册
Tabbar,
TabbarItem
}
}
</script>
<style scoped>
</style>
3.8 文件路径起别名(文件路径的引用问题)
- 修改 webpack.base.conf.js 配置文件 中的下面部分:
- 在属性中使用:引用src文件路径需要在前面加上~
- 引用外部组件