ScrollTab.ts
import { defineStore } from 'pinia'
import { onMounted, reactive, toRefs } from 'vue'
export const useScrollTabStore = defineStore('scrollTab', () => {
interface iTouch {
ID: string,
text: string
}
interface iState {
TouchList: iTouch[],
current: number,
touchParent?: HTMLDivElement | null,
scrollSlide?: HTMLDivElement | null,
touchItemHeight: number,
viewHeight: number,
median: number,
scrollTop: number,
off: boolean
}
const state = reactive<iState>({
TouchList: [
{
ID: 't1',
text: '内容1'
},
{
ID: 't2',
text: '内容2'
},
{
ID: 't3',
text: '内容3'
},
{
ID: 't4',
text: '内容4'
},
{
ID: 't5',
text: '内容5'
},
{
ID: 't6',
text: '内容6'
},
{
ID: 't7',
text: '内容7'
},
{
ID: 't8',
text: '内容8'
},
{
ID: 't9',
text: '内容9'
},
{
ID: 't10',
text: '内容10'
},
{
ID: 't11',
text: '内容11'
},
{
ID: 't12',
text: '内容12'
},
{
ID: 't13',
text: '内容13'
},
{
ID: 't14',
text: '内容14'
},
{
ID: 't15',
text: '内容15'
},
{
ID: 't16',
text: '内容16'
},
{
ID: 't17',
text: '内容17'
},
{
ID: 't18',
text: '内容18'
},
{
ID: 't19',
text: '内容19'
},
{
ID: 't20',
text: '内容20'
}
],
current: 0,
touchParent: null,
scrollSlide: null,
touchItemHeight: 0,
viewHeight: 0,
median: 0,
scrollTop: 0,
off: false
});
const onSwitch = (index: number) => {
state.off = true;
// 每次点击的时候下标值
state.current = index;
if (index > state.median) {
state.touchParent?.scrollTo({
top: state.touchItemHeight * (index - 6),
behavior: 'smooth'
})
} else {
state.touchParent?.scrollTo({
top: 1,
behavior: 'smooth'
})
}
// 页面的滚动
// console.log(index*state.viewHeight,99966)
state.scrollSlide?.scrollTo({
top: index * state.viewHeight,
behavior: 'smooth'
})
}
const onScroll = () => {
if (state.off) return;
state.scrollTop = state.scrollSlide!.scrollTop;
// 直接除 得出下标 当前的滚动值/ 盒子高度
state.TouchList.forEach((_, index: number) => {
if (state.scrollTop >= index * state.viewHeight) {
state.current = index;
}
})
// 右侧滑动,左侧可以跟着滚动
if (state.current >= state.median) {
state.touchParent?.scrollTo({
top: state.touchItemHeight * (state.current - 6),
behavior: 'smooth'
})
} else {
state.touchParent?.scrollTo({
top: 1,
// behavior: 'smooth'
})
}
// console.log(window.navigator.userAgent.toLocaleLowerCase().indexOf('android')!=-1)
// 新增
// (state.touchParent?.children[0].children[0] as HTMLDivElement).innerHTML = `${state.scrollTop}`
if (window.navigator.userAgent.toLocaleLowerCase().indexOf('android')!= -1) {
if (state.scrollTop <= 0) {
(state.touchParent?.children[0] as HTMLDivElement).innerHTML = `${state.scrollTop}`;
state.scrollSlide?.scrollTo({
top: 1,
})
}
}
}
const onStart = () => {
state.off = false
}
onMounted(() => {
// 获取屏幕可视区的高度
state.viewHeight = document.documentElement.clientHeight || document.body.clientHeight;
// 当前每个按钮的高度
state.touchItemHeight = (state.touchParent?.children[0] as HTMLDivElement).offsetHeight
// 取出中间按钮下标值
state.median = Math.floor(Math.floor(state.viewHeight / state.touchItemHeight) / 2);
// 监听右侧页面的滚动
state.scrollSlide!.onscroll = onScroll
// 监听右侧是否滚动
state.scrollSlide!.ontouchstart = onStart
// document.ontouchend = () => {
// console.log((state.touchParent?.children[0].children[0] as HTMLDivElement).innerHTML=`${state.touchParent!.scrollTop}`)
// if (state.touchParent!.scrollTop < 0) {
// state.touchParent?.scrollTo({
// top: 0,
// // behavior: 'smooth'
// })
// }
// if (state.scrollTop < 0) {
// state.touchParent?.scrollTo({
// top: 0,
// // behavior: 'smooth'
// })
// }
// }
if (window.navigator.userAgent.toLocaleLowerCase().indexOf('android') != -1) {
state.touchParent!.onscroll = () => {
// console.log(state.touchParent?.scrollTop, 99966)
if (state.touchParent!.scrollTop <= 0) {
state.touchParent?.scrollTo({
top: 1,
// behavior: 'smooth'
})
}
}
state.scrollSlide?.scrollTo({
top: 1,
})
state.touchParent?.scrollTo({
top: 1,
})
}
})
return {
...toRefs(state),
onSwitch
}
})
tab2.vue
<template>
<div class="scrolltab">
<div class="tab" ref="touchParent">
<div
v-for="(item, index) in TouchList"
@click="onSwitch(index)"
:class="index == current ? 'ac' : ''"
>
{{ item.text }}
</div>
</div>
<div class="content" ref="scrollSlide">
<div v-for="item in TouchList">{{ item.text }}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { storeToRefs } from "pinia";
import { useScrollTabStore } from "@/store";
const { TouchList, scrollSlide, touchParent, current } = storeToRefs(
useScrollTabStore()
);
const { onSwitch } = useScrollTabStore();
</script>
<style scoped lang="scss">
body {
overflow: hidden;
}
.scrolltab {
width: 100vw;
height: 100vh;
display: flex;
overflow: hidden;
.tab {
width: 30vw;
overflow: scroll;
scroll-behavior: smooth;
div {
box-sizing: border-box;
height: 200px;
border: 1px solid #000;
width: 30vw;
text-align: center;
line-height: 200px;
background-color: skyblue;
}
}
.tab::-webkit-scrollbar {
display: none;
}
.content::-webkit-scrollbar {
display: none;
}
.content {
width: 70vw;
overflow: scroll;
scroll-behavior: smooth;
div:nth-child(2n + 1) {
background-color: red;
}
div:nth-child(2n) {
background-color: pink;
}
div {
width: 70vw;
height: 100vh;
line-height: 230px;
text-align: center;
}
}
}
.ac {
background-color: #fff !important;
}
</style>
主要逻辑
左右联动其实说白了他就是选项卡,只是在选项卡的基础上升级了一些,
点击左面的时候我们需要一个中间值进行计算,那么中间值是可视区除以
每一个盒子的高度这样就能计算出来可视区能放下多少个盒子在除以2就得出了
中间的那个数是多少。我们进行判断当他的下标大于中位数的时候,让他的下标乘以每一个盒子的高度
否则就是top值为1,为啥不是0是这样的当我们先往下拉在往上拉就锁死了。当我点击左面的时候有面跟着
滚动实现逻辑就是:当我的小标*可视区的高度这样他就能滚动了。
点击左面右边跟着滚动基本都已经完成了,我们只需要监听右面的滚动事件就行了
首先要获取滚动的高度,当我滑动的时候去到他的下标值,只要当前的高度大于可视区的高度时让他取出来