preface

Because many functions and technologies of the company’s background management system are old, WE have been using VUE to reconstruct the background management system of the company recently, and we are doing commodity management and commodity addition. Learning from the interaction of adding commodities of Taobao, we need to achieve a simple effect of top drawing, anchor point and rolling highlight button.

demand

  1. Scroll to the top of the page to achieve an element fixed to the top effect
  2. Click a button and the page scrolls to the appropriate location
  3. Scroll the page and highlight the corresponding buttons when you reach a certain location

Element ceiling implementation

There are three ways to get the top effect of elements by checking relevant materials and testing (another is jquery method, which will not be introduced here).

1, Use position:sticky

1. What is position:sticky?

Sticky positioning elements are equivalent to a combination of position:relative and position:sticky. Limited by parent elements, they can present different page effects under different conditions

2. How to use sticky?

The sticky element is completely restricted to the parent element and can be used under the following conditions: 1. The overflow of the parent element of the sticky element can only be set to visible, otherwise there will be no sticky effect. 2. The parent element of the sticky element cannot be set to a fixed height, otherwise there will be no sticky effect. Unlike the standard fixed element, it does not leave the document stream. 4. An element that is sticky cannot add a parent element that contains only itself, resulting in no sticky effect. If the sticky elements in the same parent element have the same location value, they will overlap. If they belong to different parent elements, the previous elements will be squeezed out to form the effect of sequential placeholder. The specific implementation effect is as follows:

.sticky-box{ position: sticky; position: -webkit-sticky; top: 60px; // can be set dynamically with js}Copy the code

3. The compatibility

You can see the compatibility by looking at Can I Use:

Use offsetTop

Htmlelement. offsetTop is a read-only property that returns the distance of the current element relative to the top inner margin of its offsetParent element. Therefore, we need to pay attention to the offset of locating the parent element in the process of listening to the page scroll, which can be written as follows:

    // Get the offsetTop of the current element
    getOffsetTop(obj) {
      let offsetTop = 0;
      while(obj ! =window.document.body && obj ! =null) {
        offsetTop += obj.offsetTop;
        obj = obj.offsetParent;
      }
      return offsetTop;
    }
Copy the code

Add an event to vue’s Mounted lifecycle function that listens for the event to scroll:

 mounted() {
    /** Prevents page jitter when the element becomes fixed by adding a parent element of the same height */
    this.tabsHeight = this.$refs.elTabs.offsetHeight;
    window.addEventListener("scroll".this.handleScroll);
  },
  destroyed() {
    // To leave the page, remove the listening event
    window.removeEventListener("scroll".this.handleScroll);
  },
   methods: {
    /** scroll events */
    handleScroll() {
        // Get the height of the page scroll bar
        let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
        let offsetTop = this.getOffsetTop(this.$refs.elTabs);
        this.isFixed = scrollTop > offsetTop; }}Copy the code

Also, if this method is used many times in the project, it can be packaged as a component

GetBoundingClientRect ().top

GetBoundingClientRect ().top gets the position of the element relative to the viewport (the browser window), as compared to offsetTop. This method does not take into account the height of the parent element or the scroll bar of the page. This element can be processed directly as follows: /* handleScroll() {/* getBoundingClientRect(). Top Gets the height of an element from the top of the browser, Does not contain the rolling distance * / let tabOffsetTop = this. $refs. StickyBox. GetBoundingClientRect () the top; this.isFixed = tabOffsetTop < this.offsetTop }

     /** scroll events */
    handleScroll() {
      /** * getBoundingClientRect().top Gets the height of an element from the top of the browser, excluding the scrolling distance this.offsetTop represents the conditional value between the top element and the top
      let tabOffsetTop = this.$refs.stickyBox.getBoundingClientRect().top;
      this.isFixed = tabOffsetTop < this.offsetTop
    }
Copy the code

The anchor point positioning

Click the corresponding button to scroll the page to the corresponding position. At present, I know that there are two ways to realize this function: 1. 2. Use JS to simulate anchor point positioning

Use the A label for location

This is a common positioning method that can be implemented in two ways: 1. Link to the specified element’s ID 2 via the href attribute. The other is to add an A tag and link the href attribute to the A tag’s name attribute

  <a href="#view1"> button 1</a> <a href="#view2"> button 1</a> <div id="view1"> View 1</div> <div><a name="view2"2 > view < / a > < / div >Copy the code

This method is simple and supports the location of any tag. However, the location of tag A changes the hash of the route. If there is a related route, the route is redirected

Use JS to simulate anchor location

The element’s scrollTop value can be obtained by using js to scroll to the specified position, and the anchor position can be achieved by using the elder-UI el-tabs component.

<! -- html --> <el-tabs v-model="activeName" type="card" @tab-click="tabClick"> <el-tab-pane :label="item.name" :name="item.key" v-for="item in tabList" :key="item.key"></el-tab-pane> </el-tabs> <! GetOffsetTop (obj) {let offsetTop = 0; while (obj ! = window.document.body && obj ! = null) { offsetTop += obj.offsetTop; obj = obj.offsetParent; } return offsetTop; }, <! -- Anchor click event --> <! TabClick (e) {let _this = this; This. index = parseInt(e.index); // Get the currently selected index for scrolling to highlight this.index = parseInt(e.index); // Given an identifier, anchor events do not trigger scrolling this.isScroll = false; this.isChange = false; $ref = this.getoffSetTop (this.$refs[this.activename]); let scrollTop = offsetTop - this.fixedHeight; window.scrollTo({ top: scrollTop }); }Copy the code

ScrollIntoView. Element.scrollintoview () allows the current Element to scroll into the viewable area of the browser window. It also supports dynamic effects, but it does not support setting the scroll distance from the top. But it’s great for things that go to the top

Scroll the highlight button

As the user scrolls the content area, highlight the button corresponding to the element closest to the button component. By listening to scroll events, obtain the offsetTop value of the currently selected TAB and the scrollTop value of the current page, judge whether to scroll up or down, and perform different processing, as follows:

// Page scrolling to do
handleScroll() {
    let scrollTop =
        window.pageYOffset ||
        document.documentElement.scrollTop ||
        document.body.scrollTop;
      this.scrollTop = scrollTop;
      <! --isScroll will be used to prevent anchor events from triggering page scroll -->if (! this.isScroll) return; /** * height of the scrollTop page * offsetTop offsetTop * offsetHeight height of the currently selected TAB element */ let offsetTop = this.getOffsetTop(this.$refs[this.activeName]); let offsetHeight = this.$refs[this.activeName].offsetHeight; let actuaTop = scrollTop + this.fixedHeight; let length = this.tabList.length; /** * Select TAB */ if (actuaTop)< offsetTop && this.index > 0) {
        this.index = this.index - 1;
        this.activeName = this.tabList[this.index].key;
      } else if (this.index < length && actuaTop >offsetTop + offsetHeight) { this.index = this.index + 1; this.activeName = this.tabList[this.index].key; }}Copy the code

Performance optimization

Reading properties from a page results in page reflow (we’ll summarize the actions that cause page reflow and repaint next time), and excessive reflow can degrade page performance, so we should minimize the number of reflows in order to give the user a better experience. If the product is comfortable with delays, you can use throttling functions to control the execution of functions once in a certain period of time (throttling functions can be throttled using the throttling methods encapsulated in Lodash.js).

conclusion

All three of the requirements have been implemented. There may be a better solution, but if you have a better way to implement these three requirements, please leave a comment, but I also learned something from them. 2. Related attributes of scrollTop, offsetTop, getBoundingClientRect(), scrollTo, scrollIntoView 3. Anchor time and scrolling highlight events caused by conflict handling, etc