This is the 12th day of my participation in Gwen Challenge

Lynne, a front-end development engineer who can cry, love and laugh forever. In the Internet wave, love life and technology.

preface

Firstly, describe the problem. The application scenarios are as follows:

As the scroll bar moves, the TAB will be switched. When the TAB is switched, the height of the content corresponding to the TAB changes.

This can be done with a simple anchor position, but if you want a smooth content scrolling switch the best use of scrollIntoView to achieve, and to achieve TAB with the scroll bar to switch the need to listen to the current page scrolling.

Next, take a piece of code as an example to analyze the implementation ideas.

<template> <div class="box"> <div class="tab" ref="tab"> <div v-for="(item, index) in tabs" :key="index"> <div :class="{ active: active === index }" @click="switchTab(index)"> {{ item }} </div> </div> </div> <div class="cont" ref="cont"> <div <div class="cont_2" ref="cont_2"> <div class="cont_3" </div> <div class=" backTop" @click="backTop"></div> </template> <script> export default {  data() { return { tabs: ["tab1", "tab2", "tab3"], active: 0, cont1: null, cont2: null, cont3: null, isClickTab: false }; }, the methods: {backTop () {/ / back to the top this. Cont1. ScrollIntoView ({block: "start", behaviors: "smooth"}); }, switchTab (index) {/ / based on the current index to switch to the corresponding page content if (index = = = 0) {this. Cont1. ScrollIntoView ({block: "start", behaviors: "smooth" }); } else if (index === 1) { this.cont2.scrollIntoView({ block: "start", behavior: "smooth" }); } else { this.cont3.scrollIntoView({ block: "start", behavior: "smooth" }); } } }, mounted() { this.cont1 = this.$refs["cont_1"]; this.cont2 = this.$refs["cont_2"]; this.cont3 = this.$refs["cont_3"]; const tabH = this.$refs["tab"].offsetHeight; $refs["cont"]. AddEventListener ("scroll", () => { if (this.cont3.getBoundingClientRect().top <= tabH) { this.active = 2; return false; } if (this.cont2.getBoundingClientRect().top <= tabH) { this.active = 1; return false; } if (this.cont1.getBoundingClientRect().top <= tabH) { this.active = 0; }}); }}; </script> <style lang="scss" scoped> .box { font-size: 28px; overflow-x: auto; height: 100vh; display: -webkit-flex; display: flex; flex-direction: column; overflow-y: hidden; .tab { height: 88px; background: #fff; line-height: 88px; color: #666; display: -webkit-flex; display: flex; justify-content: space-around; .active { font-size: 32px; color: #333; &::after { display: block; content: ""; width: 36px; height: 6px; margin: auto; margin-top: -10px; background: rgba(255, 51, 0, 1); border-radius: 3px; } } } .cont { height: 300px; flex-grow: 1; overflow: auto; .cont_1 { height: 400px; background: pink; } .cont_2 { height: 800px; background: yellow; } .cont_3 { height: 100%; background: lightgreen; } } .back-top { width: 80px; height: 80px; background: url(.. /.. /assets/back-top.png) center / 100% 100% no-repeat; border-radius: 50%; position: fixed; bottom: 120px; right: 32px; } } </style>Copy the code

This code is a reference to the Internet, relatively simple, because the number of TAB items is fixed, we only need to switch according to the TAB click index and listening height switch to the corresponding index TAB.

But what if the number of elements in the array TAB is unknown? This quantity-indeterminate scenario is more general, and the generic code implementation flow is abstracted.

Here’s an example:

<div class="box">
 <div class="tab" ref="tab">
  <div v-for="(item, index) in tabs" :key="index">
    <div :class="{ active: active === index }" @click="switchTab(index)">
      {{ item }}
    </div>
  </div>
 </div>
 <div class="tab-content-list">
   <tab-content :id="`to-${index}`" v-for="(data, index) in dataList" :key="index" :resData="data" ref="content" />
 </div>
</div>
Copy the code

Smooth scrolling during TAB switching

Tab-content receives the content of the parent component for display:

props: {
  resData: Object
}
Copy the code

Use the scrollIntoView method for smooth scrolling:

methods: {switchTab(index) {this.clickedIndex = index // Locate the contents of the current TAB document.getElementById(`to-${clickedIndex}`).scrollIntoView({ block: 'start', behavior: 'smooth' }) } }Copy the code

Monitor scrolling for TAB switching

Mounted Collects the height of the scroll element and initialmounts the scroll listener:

This.isslide = false // If () {this.scrollinit () this.isslide = false // If () {this.scrollinit () this.isslide = false this.$refs.content.map((item, Index) => {return item.offsetTop}) setTimeout(() => {this.isSlide = false}, 600)}Copy the code

Specific methods to achieve:

methods: {{/ / monitor rolling high scrollInit (). This throttleGetScrollTop = _. Throttle (enclosing getScrollTop, 100) this.throttleGetScrollTop() window.addEventListener('scroll', this.throttleGetScrollTop, true) }, Async getScrollTop () {const scrollTop = document.getelementById ('privilage-list').scrolltop // Gets the current scroll content corresponding tabIndex const currentIndex = await this. SlotsTopList. FindIndex ((top, index) => { return scrollTop >= this.slotsTopList[index + 1] && scrollTop < this.slotsTopList[index + 2] }) if (this.isSlide) return this.clickedIndex = currentIndex + 1 } }Copy the code

There is a small problem that scrolling listening will also occur during the scrolling while clicking, leading to a TAB switching back and forth. However, there is no way to know exactly the event of clicking smooth scrolling, so I added a mark and delay in the time of clicking TAB switching to avoid repeated listening:

SetTimeout (() => {this.isSlide = false}, 600)Copy the code

Then add if (this.isslide) return to the scrolllistening height time.

conclusion

The above is the realization principle and process of page scrolling anchor positioning TAB. The most important is to judge the content area in the current viewport by listening to the window scrolling event and by the scrolling height, so as to operate the state conversion in the corresponding navigation menu. Clicking on the navigation menu triggers scrolling, corresponding to this.

Of course, my solution to the repeated monitoring in the smooth scrolling process is not perfect, if you have better ideas and suggestions, welcome to leave a message ~~~

Thank ~ ~ ~