uniapp+vue3+ts --微信小程序tab导航可以上下滚动选中选项组件代码

news/2024/7/10 0:52:22 标签: uni-app, 微信小程序, typescript, vue

vue3ts_tab_0">uniapp+vue3+ts --微信小程序tab导航可以上下滚动选中选项组件代码

废话不多说,直接上代码。

组件代码:

<template>
    <view class="scroll-tabs-container">
        <view class="radiusz bg-white pt-[10rpx] z-[999]" :class="{ 'scroll-tabs-sticky': sticky }">
            <u-tabs
                id="tabScrollTop"
                ref="tabScrollTop"
                :list="tabs"
                :current="active"
                @change="handleChangeTab"
                :active-color="mainColor"
                bg-color="transparent"
                :bar-width="90"
                font-size="24"
                :gutter="26"
                name="title"
            >
            </u-tabs>
        </view>
        <view class="content">
            <view
                class="px-[20rpx] pt-[20rpx] pb-[40rpx] w-full bg-white mb-[30rpx] box-border"
                v-for="(item, index) in tabs"
                :key="item.id"
                :class="'tabs' + index"
            >
                <view v-if="item.is_show == 1">
                    <view class="text-center"
                        ><text class="pr-[10rpx]">———</text>{{ item.title
                        }}<text class="pl-[10rpx]">———</text></view
                    >
                    <view class="mt-[40rpx]">
                        <u-parse :html="item.description"></u-parse>
                    </view>
                    <view class="mt-[40rpx]"
                        ><apply-btn
                            :customClass="customClass"
                            btnText=""
                            @popTrue="popTrue"
                        ></apply-btn
                    ></view>
                </view>
            </view>
        </view>
    </view>
</template>

<script lang="ts" setup>
const { proxy } = getCurrentInstance() as any
import cache from '@/utils/cache'
import { onShow } from '@dcloudio/uni-app'
/**
 * @description props参数说明
 * @property [number] scrollTop 外部传入的滚动条高度
 * @property [array] tabs tabs
 * @property [number] current 设置默认的tabIndex
 * @property [number]  stickyTop 固定定位的高度
 * @property [boolean] sticky 是否设置tab为固定定位
 * @property [number] itemOffsetTop 自定义滚动相隔间距,到达会切换tab
 * @property [object]  tabOptions tab的配置
 * @property [boolean] scrollTab 滚动时是否切换到指定的tab
 * @property [boolean] clickScroll 点击时是否滚动到相应位置
 * @property [number ] duration  滚动持续时长
 * @property [number] offsetTop 点击滚动到某一模块时的偏离值,每次点击滚动都会减去这个偏离值,这个值的单位是px,
 */
const mainColor = ref(cache.get('btnCon').btn_bgColor)
const customClass = ref('m-auto') //按钮样式
const props = defineProps({
    value: {
        type: String || Number,
        default: null
    },
    scrollTab: {
        type: Boolean,
        default: true
    },
    clickScroll: {
        type: Boolean,
        default: true
    },
    scrollTop: {
        type: Number || String,
        default: null
    },
    tabs: {
        type: Array,
        default: () => [] as any[]
    },
    // 设置默认的tabIndex
    current: {
        type: Number,
        default: 0
    },
    stickyTop: {
        type: String,
        default: null
    },
    // 是否将tab设为固定定位
    sticky: {
        type: Boolean,
        default: true
    },
    // 自定义间距 ,当 top小于等于这个距离的时候会切换tab
    itemOffsetTop: {
        type: Number,
        default: 60
    },
    tabOptions: {
        type: Object,
        default: () => ({})
    },
    duration: {
        type: Number,
        default: 300
    },
    offsetTop: {
        type: Number,
        default: 0
    }
})
const tabTopHeight = ref(0)
const active = ref(0)
const click = ref(false)
const timer = ref()
watch(
    [() => props.scrollTop, () => active.value],
    ([newScrollTop, newActive], [oldScrollTop, oldActive]) => {
        if (newScrollTop) {
            if (!click.value) {
                scrollToTab()
            }
        }
        if (newActive != oldActive) {
            nextTick(() => {
                scrollToElement()
            })
        }
    },
    { immediate: true }
)

onMounted(() => {
    getScrollTabTopHeight()
})
onShow(() => {
    isPopup.value = false
})
/**
 * @description: 跳转加盟申请页面
 * @param {*} isLogin 是否登陆
 * @return {*}
 */
const popTrue = (isLogin: boolean) => {
    if (!isLogin) {
        isPopup.value = !isLogin
    } else {
        uni.navigateTo({
            url: linkUrl.value
        })
    }
}

const getScrollTabTopHeight = async () => {
    // 获取tab的高度
    const query = (await createSelectorQueryForThis('#tabScrollTop', false)) as any
    if (!query) return
    tabTopHeight.value = query.height
}

const createSelectorQueryForThis = (selector: string, all: any) => {
    return new Promise((resolve) => {
        proxy
            .createSelectorQuery()
            [all ? 'selectAll' : 'select'](selector)
            .boundingClientRect((rect: any) => {
                resolve(rect)
            })
            .exec()
    })
}

const createSelectorQuery = (selector: any, all: any) => {
    return new Promise((resolve) => {
        proxy
            .createSelectorQuery()
            [all ? 'selectAll' : 'select'](selector)
            .boundingClientRect((rect: any) => {
                resolve(rect)
            })
            .exec()
    })
}
const emit = defineEmits<{
    (event: 'onChange', index: number): void
    (event: 'input', active: any): void
}>()
const handleChangeTab = (index: any) => {
    active.value = index
    click.value = true
}
// 点击滑动到指定元素
const scrollToElement = async () => {
    if (!click.value) return false
    const tab = props.tabs[active.value]
    if (!tab) return
    const { scroll_id } = tab as any
    if (!scroll_id) return false
    clearTimeout(timer.value)
    const queryData = (await createSelectorQuery(`.${scroll_id}`, false)) as any
    if (tabTopHeight.value === 0) await getScrollTabTopHeight()
    if (!queryData) {
        click.value = true
        return false
    }
    let scrollTop = props.scrollTop + queryData.top - props.offsetTop
    scrollTop -= tabTopHeight.value
    // 页面滚动函数
    uni.pageScrollTo({
        scrollTop,
        duration: props.duration,
        success: () => {
            timer.value = setTimeout(() => {
                click.value = false
            }, props.duration + 500)
        }
    })
}
const scrollToTab = async () => {
    if (!props.scrollTab && !click.value) return false
    const length = props.tabs.length
    let allClass = ''
    for (let i = 0; i < length; i++) {
        const { scroll_id } = props.tabs[i] as any
        allClass += i < length - 1 ? `.${scroll_id},` : `.${scroll_id}`
    }
    const queryData = (await createSelectorQuery(allClass, true)) as any

    for (let i = 0; i < queryData.length; i++) {
        if (queryData[i].top <= props.itemOffsetTop) {
            active.value = i
        }
    }
}
</script>

<style lang="scss" scoped>
.scroll-tabs-container {
    .status_bar {
        display: none;
        // height: var(--status-bar-height);
    }

    .scroll-tabs-sticky {
        z-index: 9999;
        overflow: hidden;
        -webkit-transform: translateZ(0);
        transform: translate3d(0, 0, 0);
        background: white;
    }
}
.radiusz {
    border-radius: 26rpx 26rpx 0 0;
    margin-top: -98rpx;
    border-bottom: 2px solid #eee;
    position: fixed;
    width: 100%;
}
</style>

页面调用代码:

<template>
  <view class="bg-[#F3F4F6] w-full">
     <scroll-tabs
           :value="current"
           :tabs="graphicIntroduction"
           :tabOptions="{ label: 'title', activeColor: '#222', barColor: '#ff9f0f' }"
           :offsetTop="180"
           :scrollTop="scrollTop"
           :sticky="true"
           :itemOffsetTop="300 + statusBarHeight"
           :clickScroll="clickScroll"
       >
       </scroll-tabs>
   </view>
 </template>
 <script lang="ts" setup>
import { getMiniNavigation } from '@/api/shop'
import { onLoad, onPageScroll } from '@dcloudio/uni-app'

const bannerImg = ref('')
const graphicIntroduction = ref([]) as any
const current = ref(0) // tab默认索引

const scrollTop = ref(0)
const clickScroll = ref(false)
const stickyTop = ref()
const statusBarHeight = ref()
onPageScroll((e: any) => {
    scrollTop.value = e.scrollTop
})

onLoad(() => {
    getMiniNavigationData()
    // getHeight()
    uni.getSystemInfo({
        success: function (e: any) {
            stickyTop.value = e.statusBarHeight + 44 + 'px'
            statusBarHeight.value = e.statusBarHeight
        }
    })
})

/**
 * @description: 获取首页轮播图和图文介绍
 * @return {*}
 */
const getMiniNavigationData = async () => {
    const { data } = await getMiniNavigation({ type: 'plan' })
    bannerImg.value = data.bannerImg
    const list = data.graphicIntroduction
    list.forEach((item: any) => {
        if (item.is_show == 1) {
            graphicIntroduction.value.push(item)
        }
    })
    graphicIntroduction.value.forEach((item: any, index: number) => {
        item.scroll_id = `tabs${index}`
    })
}
</script>

效果图:
在这里插入图片描述


http://www.niftyadmin.cn/n/5343509.html

相关文章

JavaSE核心基础-二维数组-笔记

1.二维数组概述 所谓二维数组就是数组中的数组&#xff0c;它的定义格式和一维数组很像。可以保存更多同类型的数据。二维数组的每一个元素是一个一维数组。 2. 二维数组定义的三种格式以及使用 1&#xff09;格式1&#xff08;动态初始化&#xff09;&#xff1a; int[][] a…

开始学习vue2(Vue方法)

一、过滤器 过滤器&#xff08;Filters&#xff09;是 vue 为开发者提供的功能&#xff0c;常用于文本的格式 化。过滤器可以用在两个地方&#xff1a;插值表达式 和 v-bind 属性绑定。 过滤器应该被添加在 JavaScript 表达式的尾部&#xff0c;由“管道符 ”进行 调用&#…

JAVA的基础面试三

1.何为Spring Bean容器?Spring Bean容器与Spring IOC 容器有什么不同吗? 答&#xff1a;用于创建bean对象,管理bean对象的那个容器 Spring IOC 容器本质上指的的就是Spring Bean容器, Spring Bean容器中最核心一个机制是IOC机制( 控制反转),所以有时候又将springbean容器称之…

数据库优化系列教程(8)一容灾与高可用性

容灾与高可用性&#xff08;Disaster Recovery and High Availability&#xff09; 容灾和高可用性是数据库系统设计中关键的概念&#xff0c;旨在确保系统在面临灾难性事件或硬件故障时能够保持可用&#xff0c;并能够在短时间内恢复正常运行。 容灾&#xff08;Disaster Reco…

ubuntu 各版本图形界面和命令行切换快捷键介绍

文章目录 前言一、ubuntu 图形界面和命令行模式切换的快捷键1. ubuntu 16.042. ubuntu 18.043. ubuntu 20.044. ubuntu 22.04 总结 前言 本文主要介绍如何使用快捷键进行ubuntu 的图形界面和命令行模式切换&#xff0c;涉及如下 几个ubuntu 版本 ubuntu16.04 ubuntu18.04 ubun…

【心得】java从CC1链入门CC链个人笔记

来劲了&#xff0c;感觉离真正的CTF又近了一步。 本文仅从一个萌新的角度去谈&#xff0c;如有纰漏&#xff0c;纯属蒟蒻。 目录 CC链概念 CC链学习前置知识 CC1链 Version1 Version2 Version3 CC链概念 CC链 Commons Collections apache组织发布的开源库 里面主要对…

【进口控制器替代】基于Zynq-7020 FPGA的NI 8槽CompactRIO控制器

667 MHz双核CPU&#xff0c;512 MB DRAM&#xff0c;1 GB存储容量&#xff0c;Zynq-7020 FPGA&#xff0c;更宽工作温度范围&#xff0c;8槽CompactRIO控制器 cRIO-9068是一款坚固耐用的无风扇嵌入式控制器&#xff0c;可用于高级控制和监测应用。这款软件设计控制器搭载FPGA、…

【数据库】第三章 MySQL库表操作

3.1 SQL语句基础&#xff08;SQL命令&#xff09; 3.1.1 SQL简介 SQL&#xff1a;结构化查询语言(Structured Query Language)&#xff0c;在关系型数据库上执行数据操作&#xff0c;数据检索以及数据维护的标准化语言。使用SQL语句&#xff0c;程序员和数据库管理员可以完成…