当前位置:   article > 正文

uni_app组件实现tab选项卡滑动切换,支持默认选中,vue3+ts+setup_uniapp支持滑动和点击的tab选项卡

uniapp支持滑动和点击的tab选项卡

效果截图:

前言:

最近开发小程序,需要用到tabs组件,在标签多的时候,可以左右滑动。在插件库找到uView UI,但是这个库插件体积不算太小,小程序尽可能需要减少包体积,于是就打算自己封装一下。

主要能力:选中的tab会自动移动到组件的中间位置,支持默认选中第几个tab,可联动获取数据,支持和swiper联动使用。

主要方法:scroll-view

  1. scroll-x:true //允许横向滚动
  2. scroll-left //设置横向滚动条位置
  3. scroll-with-animation //在设置滚动条位置时使用动画过渡

tabs接受的参数props,tablist是父组件传递过来的tab数组,defaultsSelectIndex默认选中的第几个tab。

<tabs :tablist='list' :defaultSelectIndex='defaultSelectIndex' @select='change'></tabs>

计算每个tab的宽度

  1. onMounted(() => {
  2. const query = uni.createSelectorQuery().in(getCurrentInstance());
  3. query.selectAll('.tabs-scroll_item').boundingClientRect((data:Array<UniApp.NodeInfo>) => {
  4. let dataLen = data.length;
  5. for (let i = 0; i < dataLen; i++) {
  6. // scroll-view 子元素组件距离左边栏的距离
  7. itemList.value[i].left = data[i].left;
  8. // scroll-view 子元素组件宽度
  9. itemList.value[i].width = data[i].width
  10. }
  11. }).exec()
  12. })

select选中的tab暴露给父组件的方法。

  1. const emits=defineEmits<{
  2. (e : 'select',value : ItabItem) : void
  3. }>()

隐藏滑动条

  1. /* 隐藏滚动条*/
  2. ::v-deep.uni-scroll-view::-webkit-scrollbar {
  3. display: none
  4. }

组件实现代码tabs.vue

  1. <template>
  2. <view class="nav">
  3. <scroll-view class="tabs" scroll-x="true" scroll-with-animation :scroll-left="scrollLeft">
  4. <view class="tabs-scroll">
  5. <view class="tabs-scroll_item" v-for=" (item,index) in itemList" :key="index"
  6. :class="{'active':selectIndex==index}" @click="chenked(index)">
  7. {{item.title}}
  8. </view>
  9. </view>
  10. </scroll-view>
  11. </view>
  12. </template>
  13. <script setup lang="ts">
  14. import { getCurrentInstance, onMounted, ref, watch } from "vue";
  15. const scrollLeft = ref<number>(0)
  16. const selectIndex = ref<number>(0)
  17. const itemList = ref<Array<ItabItem>>()
  18. interface ItabItem {
  19. title : string
  20. width ?: number
  21. left ?: number
  22. id : number
  23. }
  24. interface Iprops {
  25. tablist : Array<ItabItem>
  26. defaultSelectIndex ?: number
  27. }
  28. const props = withDefaults(defineProps<Iprops>(), {
  29. tablist: () => [],
  30. defaultSelectIndex: 6
  31. })
  32. const emits=defineEmits<{
  33. (e : 'select',value : ItabItem) : void
  34. }>()
  35. const chenked = (index:number) => {
  36. selectIndex.value = index
  37. scrollLeft.value = 0
  38. for (let i = 0; i < index - 2; i++) {
  39. scrollLeft.value = scrollLeft.value + itemList.value[i]?.width
  40. }
  41. emits('select',props.tablist[index])
  42. }
  43. onMounted(() => {
  44. const query = uni.createSelectorQuery().in(getCurrentInstance());
  45. query.selectAll('.tabs-scroll_item').boundingClientRect((data:Array<UniApp.NodeInfo>) => {
  46. let dataLen = data.length;
  47. for (let i = 0; i < dataLen; i++) {
  48. // scroll-view 子元素组件距离左边栏的距离
  49. itemList.value[i].left = data[i].left;
  50. // scroll-view 子元素组件宽度
  51. itemList.value[i].width = data[i].width
  52. }
  53. }).exec()
  54. })
  55. watch(() => [props.tablist, props.defaultSelectIndex], () => {
  56. itemList.value = props.tablist
  57. selectIndex.value = props.defaultSelectIndex
  58. if(props.defaultSelectIndex!==0){
  59. setTimeout(()=>{
  60. chenked(props.defaultSelectIndex)
  61. },50)
  62. }
  63. }, {
  64. immediate: true
  65. })
  66. </script>
  67. <style lang="scss" scoped>
  68. .nav {
  69. background-color: rgba(0, 0, 0, .1);
  70. position: fixed;
  71. z-index: 99;
  72. width: 100%;
  73. align-items: center;
  74. height: 100rpx;
  75. .tabs {
  76. flex: 1;
  77. overflow: hidden;
  78. box-sizing: border-box;
  79. padding-left: 30rpx;
  80. padding-right: 30rpx;
  81. .tabs-scroll {
  82. display: flex;
  83. align-items: center;
  84. flex-wrap: nowrap;
  85. box-sizing: border-box;
  86. .tabs-scroll_item {
  87. line-height: 60rpx;
  88. margin-right: 35rpx;
  89. flex-shrink: 0;
  90. padding-bottom: 10px;
  91. display: flex;
  92. justify-content: center;
  93. font-size: 16px;
  94. padding-top: 10px;
  95. }
  96. }
  97. }
  98. }
  99. .active {
  100. position: relative;
  101. color: #333;
  102. font-weight: 800;
  103. }
  104. .active::after {
  105. content: "";
  106. position: absolute;
  107. width: 40rpx;
  108. height: 8rpx;
  109. border-radius: 8rpx;
  110. background-color: #333;
  111. left: 0px;
  112. right: 0px;
  113. bottom: 0px;
  114. margin: auto;
  115. }
  116. /* 隐藏滚动条,但依旧具备可以滚动的功能 */
  117. ::v-deep.uni-scroll-view::-webkit-scrollbar {
  118. display: none
  119. }
  120. </style>

使用方法index.vue

  1. <template>
  2. <view>
  3. <text style="text-align: center;width: 100%;display: block;"> 标题</text>
  4. <tabs :tablist='list' :defaultSelectIndex='defaultSelectIndex' @select='change'></tabs>
  5. </view>
  6. <button @click="add" style="margin-top: 100rpx;">父组件调用切换</button>
  7. </template>
  8. <script lang="ts" setup>
  9. import { ref } from "vue";
  10. const defaultSelectIndex=ref(0)
  11. const list = ref([
  12. {
  13. id: 1,
  14. title: '直播直播',
  15. },
  16. {
  17. id: 2,
  18. title: '热门推荐',
  19. },
  20. {
  21. id: 3,
  22. title: '音乐',
  23. },
  24. {
  25. id: 4,
  26. title: '经典小说',
  27. },
  28. {
  29. id: 5,
  30. title: '看书',
  31. },
  32. {
  33. id: 6,
  34. title: '短剧',
  35. },
  36. {
  37. id: 7,
  38. title: '相声评述',
  39. },
  40. {
  41. id: 8,
  42. title: '找书广场',
  43. },
  44. ])
  45. const change=(value)=>{
  46. uni.showToast({
  47. title: value.title,
  48. duration: 2000
  49. });
  50. }
  51. const add=( )=>{
  52. defaultSelectIndex.value++
  53. }
  54. </script>
  55. <style>
  56. </style>

希望本篇文章对你有所帮助,我也是根据自己的需求封装的,你也可以根据自己的需求在该代码上进行优化。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/312383
推荐阅读
相关标签
  

闽ICP备14008679号