Tab组件【cube-ui】

  • List item

前言

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

实现点击按钮切换组件的功能,可以用vue-router实现,这里有一篇教程https://blog.csdn.net/aoteman_web/article/details/108918251就不说了,今天我们来利用cube-ui组件库里的TarBar组件和slide组件来做一个完整的上下联动的tab组件

动工

1、TabBar组件(导航栏) && slide组件(轮播组件【手动轮播】) 支持自定义插槽

<cube-tab-bar
      :showSlider="true"
      v-model="selectedLabel"
      :data="tabs"   
      ref="tabBar"
      class="border-bottom-1px">
<!--      showSlider:是否显示下划线;v-model:当前选中的label;:data:传入用于渲染的数据;-->
</cube-tab-bar>
<div class="slide-wrapper">
      <cube-slide
        :loop=false
        :auto-play=false
        :show-dots=false
        :initial-index="index"
        ref="slide"
      >
        <cube-slide-item>
          <goods></goods>
        </cube-slide-item>
        <cube-slide-item>
          <ratings></ratings>
        </cube-slide-item>
        <cube-slide-item>
          <seller></seller>
        </cube-slide-item>
      </cube-slide>
    </div>

:data传入用于渲染的数据

data() {
      return {
        index: 0,    // 当前索引,作为initial-index的prop传入
        tabs: [{
          label: '商品'
        }, {
          label: '评价'
        }, {
          label: '商家'
        }]
      }
    }

v-model使用计算属性绑定当前选中的label,
set()方法:计算cube-slide中当前的index是什么,当点击某一项label时,index随之改变,同时切换cube-slide-item

selectedLabel: {
        get() {
          return this.tabs[this.index].label
        },
        set(newVal) {
          // 计算当前的index是什么,然后作为cube-slide的props传递到initial-index
          // 当点击不同的label时index也跟着变化
          // 当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
          // 如果没有符合条件的元素返回 -1
          this.index = this.tabs.findIndex((value) => {
            return value.label === newVal
          })
        }

写到这就差不多了,不过还有上下联动的问题没解决,先来看看css有什么特别之处吧

CSS:

@import "~common/stylus/variable"

.tab
  >>> .cube-tab
    padding 10px 0
  display flex
  flex-direction column
  height 100%
  .slide-wrapper
    flex 1
    overflow hidden

>>> 三个箭头的含义(Scoped CSS的深度作用选择器)
组件库中的样式往往并不满足我们的需求,如果你希望scoped样式中的一个选择器能够作用得更深,例如影响子组件,可以使用>>>操作符
这里有详细的介绍:https://vue-loader.vuejs.org/zh/guide/scoped-css.html

原始的tab组件高度相对矮些,看起来较不美观,使用深度作用选择器添加padding样式满足我们的需求

上下联动

滑动下方的cube-slide-item时,cube-tab-bar也跟着变为对应的tab。

只需要在cube-slide监听一个事件@change=‘onChange’:Slide页面切换时触发,参数时当前页面的索引值
详细介绍:https://didi.github.io/cube-ui/#/zh-CN/docs/slide

methods: {
   onChange(current) {
   // 把current赋值给index,然后在selectedLabel重新计算index,传给initial-index找到对应的label实现联动
     this.index = current
   }
}

小缺陷:在滑动cube-slide时tar-bar 不能实时展示Slider滚动的位置

给cube-slide监听一个scroll事件:@scroll=“onScroll”,但是单纯监听一个事件是没有用的,还要给slideOptions传入一些配置。

1、首先,需要拿到移动时横坐标移动的值

<cube-slide
        :loop=false
        :auto-play=false
        :show-dots=false
        :initial-index="index"
        ref="slide"
        @change="onChange"
        @scroll="onScroll"
        :options="slideOptions"
      >
</cube-slide>
data() {
      return {
      // slideOptions配置
        slideOptions: {
          listenScroll: true,  // 是否监控scroll事件
          probeType: 3,  // 0 不派发scroll事件,1:非实时;2:滑动过程中;3:不仅在屏幕滑动的过程中,而且momentum 滚动动画运行过程中实时派发
          directionLockThreshold: 0   // 默认值为 5,锁定方向的一个阀值,一个方向持续滑动超过这个阀值之后,才会锁定另一方向,一般不需要改动。
          // 但是如果横线与竖向同时可以滚动的话,就要设这个值为0,否则滚动会受影响
        }
      }
},
methods: {
      onScroll(position) {
        console.log(position.x)
      }
}

这样,就可以拿到x值了
在这里插入图片描述
2、然后,需要在onScroll函数上做一些手脚,使Slider可以在滑动cube-slide时跟着滑动。

onScroll(position) {
        console.log(position.x)
        const tabBarWidth = this.$refs.tabBar.$el.clientWidth
        // 拿到ref为tabBar的宽度,因为cube-tab-bar是一个组件,所以用$el(element)
        const sliderWidth = this.$refs.slide.slide.scrollerWidth
        // 拿到ref为slide内部的slide对象的宽度
        const transform = -position.x / sliderWidth * tabBarWidth
        // 获取移动的位置:-position.x是slide滚动的位置 / sliderWidth 算出滚动的比例  * tabBarWidth 得到下划线应该滚动的位置
        this.$refs.tabBar.setSliderTransform(transform)
        // 调用cube-tab的setSliderTransform方法,参数就是上面得到的值
      }

但是滑动时会发现滚动不是那么自然,会有停顿的感觉,这是因为在cube-tab-bar组件中本身就有自动过渡属性,新增这个跟原有的起了冲突,只需要把原有的属性值改成false就可。

:useTransition=false

在这里插入图片描述

ok,这样就写好了,可是这样就完美了吗?效果是完美了,但是代码并不优美。一切数据(tab、slide…)都被写死了,如果未来想要新增一个tab,就必须大动干戈修改代码,因此我们把tab组件抽象与封装,让数据弹性化。

tab组件抽象与封装

把tab组件中的tabs数据抽取出来放到app.vue中然后使用props传入

1、在App.vue中

导入组件

import Goods from 'components/goods/goods'
import Seller from 'components/seller/seller'
import Ratings from 'components/ratings/ratings'

封装数据

computed: {
    tabs() {
      return [
        {
          label: '商品',
          component: Goods,
          data: {
            seller: this.seller
          }
        },
        {
          label: '评价',
          component: Ratings,
          data: {
            seller: this.seller
          }
        },
        {
          label: '商家',
          component: Seller,
          data: {
            seller: this.seller
          }
        }
      ]
    }
  }

在tab组件中传入数据

<tab :tabs="tabs"></tab>

2、在tab.vue中

props传入数据

props: {
      // 将tabs从外部传入
      tabs: {
        type: Array,
        default() {
          return {}
        }
      }
}

cube-slide-item中遍历组件tabs、传入组件tab的component和data:

<cube-slide-item v-for="(tab,index) in tabs" v-bind:key="index">
   <component :is="tab.component" :data="tab.data"></component>
</cube-slide-item>

component标签是Vue框架自定义的标签,它的用途就是可以动态绑定我们的组件,根据数据的不同更换不同的组件

这里有vue.js官方用法:https://cn.vuejs.org/v2/api/#component
在这里插入图片描述

写到这就已经完成了,但是我们还可以人为地去控制默认展示tab

App.vue:<tab :tabs="tabs" :initial-index="2"></tab>

然后在tab组件中传入

props: {
      initialIndex: { // 控制默认展示的是第几个tab
        type: Number,
        default: 0
      }
}

并将data里面的index改为this.initialIndex

index: this.initialIndex

就这样,没啥了。晚安全世界。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值