提示:这个小功能大致的逻辑:
(1)、左右两边都是scrollView布局,左右边栏每一个标题就是一个item项,我们可以同时用Promise.all实例化来初始化数据来使用uni.createSelectorQuery()获取左边每个item所需要的offsetTop和Height,同理右边栏获取每个item所需要的offsetTop和bottom等等的节点位置信息,
<template>
<view class="user_label_wrapp">
<view class="activity_top"></view>
<view class="label_border_box">
<scroll-view :scroll-y="true" :scroll-with-animation="true" class="vertical_left" :scroll-top="leftTop"
:show-scrollbar="false" id="leftHeight" >
<view class="vertical_title" :id="'left-'+index" v-for="(item, index) in labelList" :key="index" @click="navTabbar(index)">
<text :class="[navIndex == index ? 'vertical_bg' : '']">{{item.label}}</text>
</view>
</scroll-view>
<scroll-view :scroll-y="true" :scroll-with-animation="true" class="vertical-right" :show-scrollbar="false"
@scroll="scrollBtn" :scroll-into-view="'right-'+mainCur">
<view class="vertical-right-item" v-for="(item, index) in labelList" :key="index" :id="'right-'+index">
<view class="right_title">{{item.label}}</view>
<view class="vertical-label">
<view class="label-box" :class="[labelItem.select_status ? 'label_nav_ac' : '']"
v-for="(labelItem, indexItem) in item.children" :key="indexItem" @click="labelBtn(labelItem.value)">
{{labelItem.label}}
<image v-if="labelItem.select_status" class="label_icon" src="../../static/image/selected_status.png"></image>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import apis from '../../common/api.js'
import request from '../../common/common.js'
import app from '../../App.vue'
export default {
data() {
return {
navIndex: 0, // 左侧选中下标,
mainCur: "", //右侧tab下标
labelList: [], // 标签数据
leftTop: "", //左侧距离顶部
selectLabel: [],
rect: {
leftHeight: "", //左边高度(用来计算居中)
leftItem: [], //左边的每个item所需要的offsetTop和Height
rightItem: [], //右边的每个item所需要的offsetTop和bottom
}, //位置信息
}
},
onLoad() {
this.getTagListByCreator()
},
methods: {
// 实例化数据
getTabList() {
Promise.all(
[ this.initLeft(this.labelList.length, "#left-"),
this.initRight(this.labelList.length, "#right-"),
this.getRect('#leftHeight')
])
.then(([left, right, leftHeight]) => {
this.rect.leftItem = left
this.rect.rightItem = right
this.rect.leftHeight = leftHeight.height
})
},
// 初始化左边
initLeft(e, selector) {
let item = []
for (let i = 0; i < e; i++) {
this.getRect(selector + i).then(res => {
let obj = {}
obj.offsetTop = res.top
obj.height = res.height
item.push(obj)
})
}
return item
},
// 初始化右边
initRight(e, selector) {
let item = []
for (let i = 0; i < e; i++) {
this.getRect(selector + i).then(res => {
let obj = {}
obj.offsetTop = res.top
obj.bottom = res.bottom
item.push(obj)
})
}
return item
},
//获取元素属性方法
getRect(e) {
return new Promise(function(resolve, reject) {
setTimeout(() => {
uni.createSelectorQuery().select(e).boundingClientRect(res => {
resolve(res)
}).exec()
}, 10)
})
},
// tabbar选中
navTabbar(index) {
let leftItem = this.rect.leftItem
let leftHeight = this.rect.leftHeight
this.$data.navIndex = index
this.$data.mainCur = index
this.leftTop = leftItem[index].offsetTop - leftHeight / 2 + leftItem[index].height / 2
},
// 右边滑动
scrollBtn(e) {
let rightItem = this.rect.rightItem
let leftItem = this.rect.leftItem
let leftHeight = this.rect.leftHeight
let offsetTop = e.detail.scrollTop + 20
rightItem.forEach((item, index) => {
if (offsetTop > item.offsetTop && offsetTop < item.bottom) {
if (this.navIndex != index) {
this.$data.navIndex = index
this.$data.leftTop = leftItem[index].offsetTop - leftHeight / 2 + leftItem[index].height / 2
} else {
console.log('不进行改变')
}
}
})
},
// 选择label
labelBtn(value) {
this.labelList.map(item => {
item.children.map(childItem => {
if (childItem.value == value) {
if (this.selectLabel.length < 3) {
childItem.select_status = !childItem.select_status
}else{
if(this.selectLabel.length <= 3){
let bool = false
for (let i = 0; i < this.selectLabel.length; i++) {
if (this.selectLabel[i].value == value) {
childItem.select_status = !childItem.select_status
bool = true
break;
}
}
if (!bool) {
uni.showToast({
title: '最多选择三个标签',
icon: 'none',
duration: 1400,
})
}
}
}
if (childItem.select_status) {
this.selectLabel.push(childItem)
this.selectLabel = Array.from(new Set(this.selectLabel))
uni.setStorageSync('selectLabel',this.selectLabel)
} else {
this.selectLabel.map((select, index) => {
if (select.value == value) {
this.selectLabel.splice(index, 1)
}
})
}
}
})
})
},
// 获取视频所有标签
getTagListByCreator() {
uni.showLoading({
title: '正在加载...'
})
request.post(apis.getTagListByCreator, {
page: 1,
per_page: 50
}, (res) => {
res.data.tag_list.map(item => {
item.children.map(childItem => {
childItem.select_status = false
})
})
this.$data.labelList = res.data.tag_list
uni.hideLoading()
this.getTabList()
}, (error) => {
uni.showToast({
title: error.reason,
icon: 'none',
duration: 1400
})
})
}
}
}
</script>
<style lang="scss" scoped>
.user_label_wrapp{
position: relative;
height: 100vh;
overflow: hidden;
.activity_top{
width: 100%;
border-bottom: 1rpx solid #e5e5e5;
box-shadow: 0 4rpx 14rpx 1rpx #eee;
}
.label_border_box{
width: 100%;
height: 100vh;
display: flex;
flex-flow: row nowrap;
justify-content: space-evenly;
.vertical_left {
width: 25%;
height: 100vh;
border-right: 1rpx solid #e6e6e6;
box-sizing: border-box;
.vertical_title{
height: 96rpx;
line-height: 96rpx;
text-align: center;
font-size: 30rpx;
color: #292929;
.vertical_bg{
padding: 4rpx 26rpx;
background-color: #fec712;
border-radius: 30rpx;
}
}
}
.vertical-right {
width: 75%;
height: 100vh;
.vertical-right-item{
padding: 0rpx 28rpx;
font-size: 29rpx;
color: #1f1f1f;
.right_title{
padding: 28rpx 0 20rpx 0;
font-weight: bold;
font-size: 36rpx;
color: #202020;
}
.vertical-label{
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
.label-box{
width: 246rpx;
height: 62rpx;
line-height: 62rpx;
margin-bottom: 28rpx;
text-align: center;
color: #1f1f1f;
border: 1rpx solid #c5c5c5;
border-radius: 10rpx;
position: relative;
.label_icon{
position: absolute;
right: 0;
bottom: 0;
width: 29rpx;
height: 20rpx;
}
}
.label_nav_ac{
background-color: #fff8e3;
border: 1rpx solid #fec712;
}
}
}
}
}
}
</style>
以上就是该功能的内容,如果有不对之处或者有不懂,可以留言指出改正,谢谢!!!