vue3微信公众号商城项目实战系列(7)自定义底部tabbar组件

在开始之前,先看看官方对组件的定义:

 

vue3的生态非常丰富,有各种各样的开源组件库可以拿来就用,比如vant、element-ui等,本系列不使用任何第3方组件,

完全使用原生的语法来写,只为聚焦vue3技术本身,本篇写一个自定义tabbar组件,效果如下图所示:

该组件实现如下功能:

1. 底部tab项固定3个:首页、购物车、我的;

2. 购物车 tab 项加数字角标,显示购物车中商品的数量如下图,当在首页添加商品时数量要同步更改。

3.点击tab项跳转相应页面。

4. 组件的使用尽可能简单,理论上页面引用的时候只要传递一个当前页面的名称就可以了,其他逻辑全部在组件内部完成。

明确了需求,下面从0开始构建一个tabbar组件。

第1步:新建文件和文件夹,如下图:

各文件说明如下:

1. TabBar.vue 是要实现的组件文件,放在 components 目录下,以和页面区分。

2. tabBarIcon 是存放组件使用的图标目录,名称中有数字1的表示选中的 tab 项对应的图标,为彩色,所有图标如下:

3. 为了处理简洁,我们用约定的方式来处理点击 tab 项时的页面跳转,如下:

Home.vue 是首页,Cart.vue是购物车页,Mine.vue 是我的页(页面是特殊的组件,也可称页面组件,放在 views 目录),

这3个文件都要引用 TabBar.vue 这个自定义组件,根据官方的建议(见下图),组件名称用 PascalCase 的标签名。

页面引用方式如下:

 

了解了基本用法,来看TabBar.vue 代码如下:

布局块代码:

<template>
    <div class="tab-bar">
        <template v-for="item in arrTab">
            <div :class="item.tabClass" @click="onClick(item.tabName)"> 
                <img class="tab-bar-item-img" :src="item.tabIcon" />
                <span>{{ item.tabText }}</span>
            </div> 
        </template> 
    </div>    
</template>

模板中使用 v-for 循环输出各 tab 项,数组 arrTab 是在脚本块定义的 ,动态取值的部分直接绑定对象值。

其中 HTML元素的属性绑定用 " : ", 内容绑定用 "{{ }}" ,方法用 "@" 绑定。

脚本块代码:

 1 <script setup> 
 2 import { reactive, onMounted } from 'vue';
 3 import {useRouter} from 'vue-router';
 4 const router = new useRouter();
 5 function onClick(routerName){
 6     router.push({name:routerName});
 7 }
 8 
 9 const arrTab = reactive([
10     {tabName:'home', tabClass:'tab-bar-item', tabText:'首页', tabIcon:'/src/components/tabBarIcon/home.png'},
11     {tabName:'cart', tabClass:'tab-bar-item', tabText:'购物车', tabIcon:'/src/components/tabBarIcon/cart.png'},
12     {tabName:'mine', tabClass:'tab-bar-item', tabText:'我的', tabIcon:'/src/components/tabBarIcon/mine.png'},
13 ]);
14 
15 const props = defineProps(['name']) 
16 onMounted(() => {
17     console.log(props.name);
18     arrTab.forEach((item,index)=>{
19         if(item.tabName===props.name){
20             item.tabClass="tab-bar-item1";
21             item.tabIcon=item.tabIcon.replace(".png","1.png");
22         }
23     });
24 })
25 </script>

这里使用组合式API书写脚本(有setup标记),各行作用如下:

第2行:导入vue中的函数,reactive 是获取响应式对象的,onMounted 是生命周期钩子函数,在页面加载完 DOM 对象后触发,

当点击 tab 项跳转页面时需要在这个钩子函数中将选中的项置为选中的状态,见第 16~24 行的代码。

 

第3-7行:导入路由对象,当用户点 tab 项时做页面跳转。

 

第9-13行:定义响应式数组对象,一个对象只要用 reactive( ) 函数处理一下就可以做双向数据绑定,这就是响应式编程的优势之一。

布局块中的 tab 项的内容就是用这个数据对象输出的。

 

第15行:用编译宏命令defineProps( ) 给这个组件定义一个 name 属性,这样引用的页面就可以在这个组件上给name属性赋值

,props 对象就可以取到这个值,第19 行的 if 语句就是基于 这个属性值来决定哪个 tab 项用彩色图片和文字来显示的。

 

样式块代码:

<style>
.tab-bar{
    width: 100%;
    position: fixed;
    left: 0;
    bottom: 0;
    padding: 2px 0;
    border-top: solid 1px #c0c0c0;
    display: flex;
    flex-direction: row;
    justify-content: space-around;

}
.tab-bar-item{
    display: flex;
    flex-direction: column;
}
.tab-bar-item1{
    display: flex;
    flex-direction: column;
    color: #0ab2ac;
}
.tab-bar-item-img{
    width: 28px;
    height: 28px;
}
</style>

样式中 .tab-bar 要将 tabbar 绝对定位在页面底部 , 通过 "position: fixed;  left: 0; bottom: 0;" 来实现,

显示类型 为 "display: flex; "  可以很方便的给3个 tab 项 横向均匀对齐。其他的就是 css 的基本用法了。

 

 

最后,看一个 Home.vue 、 Cart.vue、Mine.vue 中的代码:

Home.vue 代码:

<template>
    <div>
        <span>公众号商城首页</span> 
        <TabBar name="home" />
    </div>    
</template>


<script setup>
import TabBar from '@/components/TabBar.vue';
 
</script>

 Cart.vue 代码:

<template>
    <div>
        <span>购物车</span> 
        <TabBar name="cart" />
    </div>    
</template>


<script setup>
import TabBar from '@/components/TabBar.vue';
 
</script>

Mine.vue 代码:

<template>
    <div>
        <span>我的</span> 
        <TabBar name="mine" />
    </div>    
</template>


<script setup>
import TabBar from '@/components/TabBar.vue';
 
</script>

这3个文件中  <TabBar name="xxxx" /> 的 name 属性就是对应  const props = defineProps(['name']) 这里的 name 字符串

,defineProps 是一个仅 <script setup> 中可用的编译宏命令,并不需要显式地导入,其传入的参数是一个字符数组

, 如果有多个属性,加到这个数组当中就可以了,形如:const props = defineProps(['name', 'title', 'text'])

,取值的时候用 props.name、props.title、props.text 就可以获取到引用页面设置的属性值了 。

 

 

 

以上就是一个简单的自定义组件的用法,这里还有一个功能 " 购物车加数字角标 " 没有实现

,留着写加购物车功能的时候再完成更合适一些。

 

posted @ 2023-04-18 14:31  屏风马  阅读(698)  评论(0编辑  收藏  举报