功能完善
很显然, TabBarItem 应该可以显示不同的图标, 可以点击切换, 当点击的时候会高亮
这里, 如果我们想做的更好用一点
- 可以自定义 TabBar 的
v-model
, 通过双向绑定一个值, 来控制具体是哪一个 Item 高亮 - 可以在 TabBar 上定义一个 route 属性, 来开启路由模式, 当点击不同的 Item 时跳转到不同的路由
# 1 给 Item 添加图标
通过 Iconfont 添加一些图标, 生成一个动态链接
//at.alicdn.com/t/font_2616292_d5miagvtro.css
1
因为这些字体图标仅仅在 Item 中使用, 可以在 Item 组件中导入
<style scoped>
@import 'http://at.alicdn.com/t/font_2616292_d5miagvtro.css';
.tab-bar-item {
flex: 1;
text-align: center;
}
</style>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
定义一个属性 icon, 在外面传入具体的图标类型
<script>
export default {
name: 'TabBarItem',
props: {
icon: {
type: String,
required: true,
},
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
在 App.vue 里, 给每一个 Item 添加 icon 属性
<template>
<div id="app">
<tab-bar>
<tab-bar-item icon="home">首页</tab-bar-item>
<tab-bar-item icon="category">分类</tab-bar-item>
<tab-bar-item icon="cart">购物车</tab-bar-item>
<tab-bar-item icon="user">我的</tab-bar-item>
</tab-bar>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
进一步调整样式
<template>
<div class="tab-bar-item">
<i :class="['iconfont', 'icon-' + icon]"></i>
<div class="title">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
props: {
icon: {
type: String,
required: true,
},
},
}
</script>
<style scoped>
@import 'http://at.alicdn.com/t/font_2616292_d5miagvtro.css';
.tab-bar-item {
flex: 1;
text-align: center;
}
.tab-bar-item i {
font-size: 20px;
}
.tab-bar-item .title {
font-size: 14px;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 2 Item 点击时高亮
<template>
<div :class="['tab-bar-item', active ? 'active' : '']" @click="onClick">
<i :class="['iconfont', 'icon-' + icon]"></i>
<div class="title">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'TabBarItem',
props: {
icon: {
type: String,
required: true,
},
},
data() {
return {
active: false,
}
},
methods: {
onClick() {
this.active = true
},
},
}
</script>
<style scoped>
@import 'http://at.alicdn.com/t/font_2616292_d5miagvtro.css';
.tab-bar-item {
flex: 1;
text-align: center;
}
.tab-bar-item i {
font-size: 20px;
}
.tab-bar-item .title {
font-size: 14px;
}
.active {
color: #1989fa;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 3 自定义 v-model
Item 只能控制自己, 不能操作它的兄弟.
只能通过父元素, 也就是 TabBar 来控制具体哪一个 Item 处于激活状态
可以通过实现 TabBar 的v-model
指定, 来实现双向绑定
自定义v-model
是通过value
属性和input
方法实现的. 因此在 TabBar 中定义value
属性
<script>
export default {
name: 'TabBar',
props: {
value: {
type: Number,
default: 0,
},
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
在 App.vue 中使用v-model
<template>
<div id="app">
<tab-bar v-model="active">
<tab-bar-item icon="home">首页</tab-bar-item>
<tab-bar-item icon="category">分类</tab-bar-item>
<tab-bar-item icon="cart">购物车</tab-bar-item>
<tab-bar-item icon="user">我的</tab-bar-item>
</tab-bar>
</div>
</template>
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
在 TabBar.vue 中监视 value 值的变化, 进而改变 Item 的 active 属性
<script>
export default {
name: 'TabBar',
props: {
value: {
type: Number,
default: 0,
},
},
watch: {
value: function() {
this.$children.forEach((item, index) => {
item.active = index == this.value
})
},
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
由于在 dom 挂载时, 也需要计算 Item 的状态, 可以封装成一个函数
<script>
export default {
name: 'TabBar',
props: {
value: {
type: Number,
default: 0,
},
},
mounted() {
this.setActive()
},
watch: {
value: 'setActive',
},
methods: {
setActive() {
this.$children.forEach((item, index) => {
item.active = index == this.value
})
},
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
在 Item 组件中, 获取当前的 index, 并触发父组件的 input 事件
methods: {
onClick() {
this.active = true
// 获取当前的index, 触发父组件的input事件
const index = this.$parent.$children.indexOf(this)
this.$parent.$emit('input', index)
},
},
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
这样就可以实现双向绑定了
# 4 路由功能
# 1) TabBar 修改
如果 TabBar 中添加了route
属性, 即可开启路由功能, 当 Item 点击时可以切换路由
props: {
value: {
type: Number,
default: 0,
},
route: Boolean,
},
1
2
3
4
5
6
7
2
3
4
5
6
7
# 2) TabBarItem 修改
<script>
export default {
name: 'TabBarItem',
props: {
icon: {
type: String,
required: true,
},
to: String,
},
data() {
return {
active: false,
}
},
methods: {
onClick() {
this.active = true
// 获取当前点击的子元素在其父组件中的索引值
const index = this.$parent.$children.indexOf(this)
this.$parent.$emit('input', index)
if (this.$parent.route) {
if (this.$route.path !== this.to && this.to)
this.$router.push(this.to)
}
},
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 3) 配置路由
const routes = [
{
path: '/home',
name: 'home',
component: () => import('@/views/home'),
},
{
path: '/category',
name: 'category',
component: () => import('@/views/category'),
},
{
path: '/cart',
name: 'cart',
component: () => import('@/views/cart'),
},
{
path: '/user',
name: 'user',
component: () => import('@/views/user'),
},
{
path: '*',
redirect: '/home',
},
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
在 Views 下创建四个页面, 并在 App.vue 中加入<router-view>
如果觉得有帮助, 可以微信扫码, 请杰哥喝杯咖啡~
上次更新: 2021/09/03, 15:32:17