To achieve the effect of clicking the title on the left and sliding to the corresponding module on the right, you need to use scroll-view for scrolling and module positioning
1. Firstly, click on the left to control and slide to the corresponding module on the right
Left render module TAB
<div class='containerleft'>
<div class='item' v-for="(item,index) in menuList" :class="index===currenIndex? 'active':''" @click='handleMenuChange(item,index)'>
<p>{{item.title}}</p>
</div>
</div>
menuList:[{name:'Recruitment data'.id:'zl'}, {name:'Promotion Tools'.id:'sx'}, {name:'University Enquiries'.id:'gx'}, {name:'Professional Exploration'.id:'zy'}, {name:'Know your job'.id:'lj'},].Copy the code
On the right, use srollView to set vertical scrolling: scroll-y=”true”, pay attention to setting the height, and use the ID of the scrollinto-view to locate the corresponding module, so as to achieve the effect of clicking on the left and sliding on the right. Meanwhile, the scrollwith-animation starts the positioning animation
<div class='containerright'>
<scroll-view scroll-y="true" style="height: 100%;" :scroll-into-view="currentid" :scroll-with-animation='true' @scroll='scroll'>
<div v-for="(item,index) in menuList" class='contentitem' :id='item.id' :key='index'>
<div class='title':class="index===positionIndex? 'positiontop':''" :style="[index===beforeIndex?positionabsolute:'']">{{item.name}}</div>
<div class='menubox'>
<div class='menuitem' v-for="(ite,ind) in Data" :key='ind' >
<image :src="ite.icon" mode="" class='icon'></image>
<p>{{ite.name}}</p>
</div>
</div>
</div>
</scroll-view>
</div>
data() {
return {
isClick:false.// Whether to click left
isShow: false.// Whether to display this page
currenIndex:0.// Now click to the left of the subscript to activate the subscript
currentid:' './ / the current ids
topArr: [].// The top distance array of each module
beforeIndex: -1.// The previous location module
positionIndex: -1.// The module needs to be located
positionabsolute: {'position':'absolute'.'bottom':'0'.'left':'0',},menuList:[
{name:'Recruitment data'.id:'zl'},
{name:'Promotion Tools'.id:'sx'},
{name:'University Enquiries'.id:'gx'},
{name:'Professional Exploration'.id:'zy'},
{name:'Know your job'.id:'lj'},].Data:[
{name:'Enrollment Plan'.icon:'https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg'},
{name:'Calendar admission'.icon:'https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg'},
{name:'Provincial control line'.icon:'https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg'},
{name:'Table of rank'.icon:'https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg'},]}; },Copy the code
2. Swipe on the right and activate the corresponding title on the left
<div class='containerleft'>
<div class='item' v-for="(item,index) in menuList" :class="index===currenIndex? 'active':''" @click='handleMenuChange(item,index)'>
<p>{{item.title}}</p>
</div>
</div>
menuList:[{name:'Recruitment data'.id:'zl'}, {name:'Promotion Tools'.id:'sx'}, {name:'University Enquiries'.id:'gx'}, {name:'Professional Exploration'.id:'zy'}, {name:'Know your job'.id:'lj'},].Copy the code
On the right hand side, I’m going to use @scroll=’scroll’ e.dail.scrolltop to get the distance from the top,
<scroll-view scroll-y="true" style="height: 100%;" :scroll-into-view="currentid" :scroll-with-animation='true' @scroll='scroll'>
Copy the code
Page rendering by id, after uni. CreateSelectorQuery () for each module array distance at the top of the distance, pay attention to use after mounted on the page
// Get the height of the module from the top
getModuleTop(){
const query = uni.createSelectorQuery().in(this);
let topArr=[];
for(var i=0; i<this.DataList.length; i++){ query.select(` #The ${this.DataList[i].id}`).boundingClientRect(data= > {
// console.log(" Get layout location info "+ json.stringify (data));
// console.log(" distance of node from top of page is "+ data.top);
const res= topArr.findIndex((item) = >{
return item===data.top
})
if(res===-1){
topArr.push(data.top)
}
}).exec();
}
setTimeout(() = >{
this.topArr=[...topArr]
},500)},Copy the code
Determine the subscript in the array range and return the subscript to control the left header via current
// Determine the subscript in the array range and return the title to the right of the subscript to locate the header
// Determine the subscript in the array range and return the subscript to control the left header
getIndex(value,arr){
return arr.findIndex((item) = >{
// console.log(item,value)
return value>=(item-300) && value<=(item)
})
},
Copy the code
3. Add position sliding effect to the right title
Position it to the head with the currently moved subscript and position it relative to the bottom of the previous box to move the page title up to the next title
<div class='title':class="index===positionIndex? 'positiontop':''" :style="[index===beforeIndex?positionabsolute:'']">{{item.title}}</div>
data(){
return {
beforeIndex: -1.// The previous location module
positionIndex: -1.// The module needs to be located
positionabsolute: {'position':'absolute'.'bottom':'0'.'left':'0',}}}Copy the code
Note that the position of the next fixed positioning title needs to be obtained in advance to set the previous fixed positioning title as relative positioning
// Control the head position
const rightres=this.getPositionIndex(e.detail.scrollTop,this.topArr)
if(e.detail.scrollTop<5) {this.beforeIndex=-1
this.positionIndex=-1
}else{
if(rightres! = = -1) {if(this.positionIndex! ==rightres){this.beforeIndex=-1
this.positionIndex=rightres
}
}else{
this.beforeIndex=-1
this.positionIndex=-1}}const rightbeforeres=this.getBeforePositionIndex(e.detail.scrollTop,this.topArr)
if(rightbeforeres! = = -1) {if(this.positionIndex! ==rightbeforeres){const index=this.positionIndex
this.beforeIndex=index
this.positionIndex=-1}}// Determine the subscript in the array range and return the title to the right of the subscript to locate the header
getPositionIndex(value,arr){
return arr.findIndex((item,index) = >{
return value>=(item-50) && value<=(item+(arr[index+1]-arr[index]-40))})},// Determine the subscript in the array range and return a fixed positioning header on the subscript relative to the bottom of its box
getBeforePositionIndex(value,arr){
return arr.findIndex((item,index) = >{
return value>=(item-60) && value<=(item+(arr[index+1]-arr[index]-60))})},Copy the code
4. All codes
<template>
<div v-if="isShow" class='toolkit-container'>
<div class='containerbox'>
<div class='containerleft'>
<div class='item' v-for="(item,index) in menuList" :class="index===currenIndex? 'active':''" @click='handleMenuChange(item,index)'>
<p>{{item.name}}</p>
</div>
</div>
<div class='containerright'>
<scroll-view scroll-y="true" style="height: 100%;" :scroll-into-view="currentid" :scroll-with-animation='true' @scroll='scroll'>
<div v-for="(item,index) in menuList" class='contentitem' :id='item.id' :key='index'>
<div class='title':class="index===positionIndex? 'positiontop':''" :style="[index===beforeIndex?positionabsolute:'']">{{item.name}}</div>
<div class='menubox'>
<div class='menuitem' v-for="(ite,ind) in Data" :key='ind' @click='handleswitch(ite)'>
<image :src="ite.icon" mode="" class='icon'></image>
<p>{{ite.name}}</p>
</div>
</div>
</div>
</scroll-view>
</div>
</div>
<div class='footer'>Journal: Guizhou Enrollment Examination Service Center</div>
</div></template> <script> import { footMixins } from "./config.js"; Export default {data() {return {isClick:false, // False, // display this page currenIndex:0, // currently click left of subindex to activate currentid: ", // currentid topArr:[], // top distance array of each module beforeIndex:-1, PositionIndex :-1, // PositionAbsolute :{'position':'absolute', 'bottom':'0', 'left':'0',}, // Test data MenuList: [{name: 'enroll data, id:' zl '}, {name: 'entrance tools, id:' sx '}, {name: 'queries in colleges and universities, id:' gx}, {name: 'professional exploration, id: "zy"}, {name:' understanding of career, id: 'lj'}, ], Data: [{name: 'enrollment plan, icon:' https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg '}, {name: 'admissions calendar year, icon:' https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg '}, {name: 'province control line, icon:' https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg '}, {name: 'seating arrangement table, icon:' https://cdn.img.up678.com/ueditor/upload/image/20211117/1637128354571050818.jpg '},]}; }, mixins: [footMixins], components: { }, watch: { isShow: function(val, oldVal) { if(val){ this.getInit() } } }, mounted(){ // this.getModuleTop() }, methods: { async getInit(){ const res = await this.$ajax({ url:'/gzsx/data/toolbox' }) if(res.code===200){ this.DataList=[...res.list] } this.DataList.map((item,index)=>{ item.id=`menu${index}` }) setTimeout(()=>{ this.getModuleTop() },200) }, HandleMenuChange (item,index){this.currentid=item.id this.currenIndex=index this.isClick=true this.beforeIndex=-1 this.positionIndex=-1 }, If (this.isclick){this.isclick =false}else{// Control the left header const res=this.getIndex(e.detail.scrollTop,this.topArr) if(res! = = 1) {enclosing currenIndex = res} / / control head positioning const rightres = this. GetPositionIndex (e.d etail. The scrollTop, enclosing topArr) if(e.detail.scrollTop<5){ this.beforeIndex=-1 this.positionIndex=-1 }else{ if(rightres! ==-1){ if(this.positionIndex! ==rightres){ this.beforeIndex=-1 this.positionIndex=rightres } }else{ this.beforeIndex=-1 this.positionIndex=-1 } } const rightbeforeres=this.getBeforePositionIndex(e.detail.scrollTop,this.topArr) if(rightbeforeres! ==-1){ if(this.positionIndex! ==rightbeforeres){ const index=this.positionIndex this.beforeIndex=index this.positionIndex=-1 } } } }, GetModuleTop (){const query = uni.createsElectorQuery ().in(this); let topArr=[]; for(var i=0; i<this.menuList.length; I ++){query.select(' #${this.datalist [I].id} ').boundingClientRect(data => {// console.log(" get layout location information "+) JSON.stringify(data)); // console.log(" distance of node from top of page is "+ data.top); const res= topArr.findIndex((item)=>{ return item===data.top }) if(res===-1){ topArr.push(data.top) } }).exec(); } setTimeout(()=>{ this.topArr=[...topArr] },500) }, GetIndex (value,arr){return arr.findIndex((item)=>{// console.log(item,value) return value>=(item-300) && value<=(item) }) }, GetPositionIndex (value,arr){return arr.findIndex((item,index)=>{return Value >=(item-50)) && value<=(item+(arr[index+1]-arr[index]-40)) }) }, GetBeforePositionIndex (value,arr){return arr.findIndex((item,index)=>{return value>=(item-60) && value<=(item+(arr[index+1]-arr[index]-60)) }) }, handleswitch(ite){ uni.navigateTo({ url:`${ite.actionTarget}` }) } } }; </script> <style lang="scss"> $fontfamily:'font-siyuan'; .toolkit-container{ height: calc(100vh - 60px); .containerbox{ display:flex; width:100%; height:92%; .containerleft{ width:38%; height:100%; background: #F8F8F8; .item{ width: 100%; height: 70px; p{ width:100%; text-align:center; height:70px; font-size: 16px; font-family: $fontfamily; font-weight: bold; color: #858585; line-height: 70px; } } .active{ background: #FFFFFF; color: #000000; position:relative; p{ color: #333; } } .active::after{ content: ''; left: 0; top: 0; position: absolute; width: 3px; height: 70px; background: #1D51FD; } } .containerright{ width:62%; height:100%; background-color:#FFFFFF; position: relative; padding-top: 19px; .contentitem{ width:100%; position: relative; .title{ width: 62vw; height: 20px; font-size: 14px; font-family: PingFangSC-Regular, PingFang SC; font-weight: 400; color: #999; line-height: 20px; padding-left: 18px; // background-color: #F8F8F8; } .positiontop{ position: fixed; top: 19px; right: 0; background-color: #FFFFFF; opacity: 1; z-index: 99; } .menubox{ display: flex; flex-wrap: wrap; padding: 23px 38px 22px 30px; justify-content: space-between; .menuitem{ flex-shrink: 1; margin-bottom: 23px; margin-right: 10px; display: flex; flex-direction: column; align-items: center; justify-content: center; .icon{ display: block; width: 47px; height: 47px; margin-bottom: 8px; } p{ text-align: center; height: 17px; font-size: 12px; font-family: PingFangSC-Regular, PingFang SC; font-weight: 500; color: #333333; line-height: 17px; } } } } } } .footer{ display: flex; align-items: center; justify-content: center; width:100%; height:8%; font-size: 14px; font-family: PingFangSC-Regular, PingFang SC; font-weight: bold; color: #BFBFBF; text-align: center; } } </style>Copy the code