vue3.0 封装Tab 标签页组件(Uniapp)

介绍

选项卡组件,用于H5,小程序等环境中,在不同的内容区域之间进行切换。

使用方式模仿vant UI

封装组件

"as-tabs":标签组

"as-tab":单个标签

基础用法

通过active设定当前激活标签对应的索引值,默认情况下启用第一个标签。

<as-tabs v-model:active="active">
  <template v-for="(item,key) in tabs" :key="key">
     <as-tab :title="item.name" :badge="item.badge">
          {{ item.name }}
     </as-tab>
   </template>
</as-tabs>
setup(){
    const tabs = reactive( [
       { name: '售后申请',badge:1 },
       { name: '处理中',badge:2 },
       { name: '待评价',badge:3 },
       { name: '申请记录',badge:4 }
   ])
   const active = ref(0)
   return { active,tabs }
}

开发思路

tab标签选项卡。按照正常的逻辑,我们只需要把不同的需要切换的内容。贴上相应的编号,然后根据不同的编号。去切换相应的内容显示。通常的tab逻辑比这个复杂。这里我们把它简化成两部分,封装tab模块用于储存内容和编号,封装tabs模块由于接收调用编号后切换对应的tab显示。

由于tabs和tab是单独封装的2个模块,从外部看他们并没有什么联系。而在内部用provide和inject实现模块之间的数据共享。

重点:由于provide和inject并不支持实时响应,代码中我们需要添加独立的数据监听控制。

tabs封装

<template>
    <view class="tabs">
        <view class="tabs__wrap">
             <view class="tabs__nav">
            <template v-for="(item,key) in AllData" :key="key">
                <view :class="['tab',key==active?'active':'']" :data-index="key" @click="handleTab">
                    <view class="text">
                        <view v-if="item.badge" class="list-num">{{item.badge}}</view>
                        <view>{{item.title}}</view>
                    </view>
                </view>
            </template>
        </view>
        </view>
        <view class="tabs__content">
            <slot></slot>
        </view>
    </view>
</template>

 

<script lang="ts">
    import { defineComponent,reactive,toRefs,provide,useSlots,ref,computed,onMounted } from 'vue'
    export default defineComponent({
        name: "as-tabs",
        props:{
            active:{
               default:0
            }
        },
        emits:['update:active','click-tab'],
        setup(props,ctx){
            const AllData = reactive([])

            const active = computed({
                get:()=>props.active,
                set:(value)=>{ctx.emit("update:active",value)}
            })

            provide('active',active)
            provide('AllData',AllData)

            const handleTab = (event:any)=>{
                active.value = event.currentTarget.dataset.index
                ctx.emit('click-tab',event)
            }

            return {
                AllData,handleTab
            }
        }
    })
</script>

 

<style lang="scss" scoped>
    .tabs {
        height: 100vh;
        width: 100%;
        box-sizing: border-box;
        .tabs__wrap {
            overflow-x: scroll;
            .tabs__nav {
                position: fixed;
                width: 100%;
                height: 88rpx;
                line-height: 88rpx;
                display: flex;
                justify-content: space-between;
                align-items: center;
                background-color: #fff;
                border-bottom: 1rpx solid #eee;
                position: relative;
                .tab {
                    font-size: 28rpx;
                    color: #233445;
                    height: 60rpx;
                    line-height: 60rpx;
                    text-align: center;
                    min-width: 130rpx;
                    padding: 0 6rpx;
                    position: relative;
                    display: flex;
                    justify-content: center;
                    border-bottom: 3px solid #fff;
                    .text {
                        width: fit-content;
                        position: relative;
                        .list-num {
                        position: absolute;
                        top: -2rpx;
                        right: -24rpx;
                        width: 30rpx;
                        height: 30rpx;
                        font-size: 20rpx;
                        background: #ff3456;
                        color: #fff;
                        /* border: 1rpx solid #ff3456; */
                        border-radius: 30rpx;
                        text-align: center;
                        line-height: 30rpx;
                    }
                    }
                    &.active {
                        color: #ff3456;
                        border-bottom: 3px solid #ff3456;
                    }

                }
            }
        }
        .tabs__content {
            box-sizing: border-box;
            height: calc(100% - 88rpx);
        }
    }
</style>

tab 封装

<template>
    <slot v-if="select"></slot>
</template>
<script lang="ts">
    import { defineComponent,reactive,toRefs,computed,inject,onMounted,nextTick,ref,effect } from 'vue'
    export default defineComponent({
        name: "as-tab",
        props:{
          title:{
              default:'标题'
          },
          badge:{
              default:undefined
          }
        },
        setup(props,ctx){
            const active = ref(inject<number>('active'))
            const allData = inject<any>('AllData')
            const key = ref(null)

            const select = computed(()=>active.value == key.value)

            onMounted(()=>{
                allData.push({
                    title:props.title,
                    badge:computed(()=>props.badge)
                })
                key.value = allData.findIndex((item:any)=>item.title == props.title )
            })


            return {
                allData,active,key,select
            }
        }
    })
</script>
<style lang="scss" scoped>
    .tab {
        font-size: 28rpx;
        color: #233445;
        height: 60rpx;
        line-height: 60rpx;
        text-align: center;
        padding: 0 6rpx;
        position: relative;
        border-bottom: 3px solid #fff;
        &.active {
            color: #ff3456;
            border-bottom: 3px solid #ff3456;
        }
    }
</style>

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值