- 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
就这样,没啥了。晚安全世界。