preface

Touch fish at work, touch fish at work, touch straight. During one debugging process, I pressed F12, which happened to be the gold digger page, entered the code into the console, and scrolled the right scroll bar several times. I found a problem as shown in the picture below:

The nuggets’ official website scroll bar bounces back to a certain position when you drag it to the bottom. Following this problem, I want to use VUE-CLI3.0 and TS to achieve the following function.

Technology stack

  • Vue – cli3.0
  • ts
  • axios

Set up the environment

npm install -g @vue/cli
vue create <name>
Copy the code

Select the required configuration items as prompted

(*) Babel
(*) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
( ) Vuex
(*) CSS Pre-processors
(*) Linter / Formatter
Copy the code

Support for TS

After setting up the environment, the project will generate two files, shims-vue.d.ts and shims-tsx.d.ts

  • shims-vue.d.tsBy default, TS does not recognize VUE
declare module '*.vue' {
  import Vue from 'vue'
  export default Vue  // let ts recognize the.vue file
}
Copy the code
  • shims-tsx.d.tsThis declaration file is allowed to be written in a VUE projectjsxCode can be used.tsxThe ending file can be ignored if it is not used in the project.
import Vue, { VNode } from 'vue'

declare global {
  namespace JSX {
    // tslint:disable no-empty-interface
    interface Element extends VNode {}
    // tslint:disable no-empty-interface
    interface ElementClass extends Vue {}
    interface IntrinsicElements {
      [elem: string] :any}}}Copy the code

Element-ui Infinite scrolling (TSX version)

The ts version is similar to the js version, and can be used directly when declaring variables and methods using the react class class. The initial data is simulated using count, and the load method is triggered when scrolling to the bottom to simulate the data returned by scrolling through the push method.

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
     <div class="infinite-list" v-infinite-scroll="load" style="overflow:auto; height:200px">
        <ElementScroll :count="count"/>
     </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import ElementScroll from './components/ElementScroll';

@Component({
  components: {
    ElementScroll
  },
})
export default class App extends Vue {
    public count = [1.2.3.4.4.5];
    public num = 0;
    /** * load */
    public load() {
        this.count.push(this.num++)
    }
}
</script>
Copy the code

In TSX, @Component is used to register components, @Prop is used to pass and verify properties, and the render method is used to render components. Since the previous V-for property is not supported, map is used instead

import { Component, Prop, Vue } from 'vue-property-decorator'
@Component
export default class ElementScroll extends Vue {
    @Prop(Array) public count! :Array<Number>;
    protected render() {
        return (
            <ul>
                {
                    this.count.map(item => {
                        return <li class="infinite-list-item">{item}</li>})}</ul>)}}Copy the code

Without further ado, take a look at the renderings:

Implement no scrolling yourself

First let’s look at the effect

Background interface data format

{
  "code": 0."data": [{"href": "https://mmbiz.qpic.cn/mmbiz_gif/ciclmTicgVuW6iaPXwMnCJVwu4oXnlxV0sNiayhYLsejBUXWaETtG81XHTkTsmBvHDZAoJd4icgNWmonk0g24QC E5Ag/0?wx_fmt=gif"."name": "Perfect for deep and light copies of JavaScript."
    },
    {
      "href": "https://mmbiz.qpic.cn/mmbiz_gif/ciclmTicgVuW6iaPXwMnCJVwu4oXnlxV0sNiayhYLsejBUXWaETtG81XHTkTsmBvHDZAoJd4icgNWmonk0g24QC E5Ag/0?wx_fmt=gif"."name": "Understand how decorators are used."
    },
    {
      "href": "https://mmbiz.qpic.cn/mmbiz_gif/ciclmTicgVuW6iaPXwMnCJVwu4oXnlxV0sNiayhYLsejBUXWaETtG81XHTkTsmBvHDZAoJd4icgNWmonk0g24QC E5Ag/0?wx_fmt=gif"."name": "Romantic Chinese Valentine's Day wins the heart of a beautiful woman."
    },
    {
      "href": "https://mmbiz.qpic.cn/mmbiz_gif/ciclmTicgVuW6iaPXwMnCJVwu4oXnlxV0sNiayhYLsejBUXWaETtG81XHTkTsmBvHDZAoJd4icgNWmonk0g24QC E5Ag/0?wx_fmt=gif"."name": "In-depth analysis of vue-Router principle, see through front-end routing."}}]Copy the code

Train of thought

The set page can display N pieces of data. We request n pieces of data to the background in the first screen page, and send the interface to the background again when the scroll bar reaches a certain position, and so on.

The first step is to get the position of the scroll bar. The height of the viewable area and the distance between the bottom of the content area and the top of the viewable area of the page. If they are equal, the browser’s scroll bar should scroll to the bottom of the page; if the difference is negative, the browser’s scroll bar has not reached the bottom of the page.

  • Gets the viewable heightclientWidth
function getView(container: HTMLElement) :any {
    return {
        width: Math.max(container.clientWidth, window.innerWidth || 0),
        height: Math.max(container.clientHeight, window.innerHeight || 0),}; }Copy the code
  • The size of the element and its position relative to the viewport getBoundingClientRect
function getHeight(container: HTMLElement, el: any) :number {
    return getView(container).height - el.getBoundingClientRect().bottom;
}
Copy the code

Using addEventListener to listen for scroll events, if the value of getHeight() reaches a specified value, we can trigger our own request to call the interface etc

Optimize the page

The idea here is that when our browser scroll bar is rolled, the scrolling content is not displayed on the page, only visible area, reduce the load of the page, first look at the effect

When the scrollbar scrolls back:

Calculate the number of items exceeding the viewable area by listening the ratio of the height of the upper part of the content area and setting the height of each directory, judge the subscript of the rendered data and the size of the items to display.

<template>
  <div class="scroll">
    <ul ref="list">
      <li v-for="(item,index) in lists" :key="index">
        <a :href="item.href" v-if="index+10>=num">{{item.name}}</a>
      </li>
    </ul>
  </div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
export default class VueScroll extends Vue {
  public list = [];
  public lists = [];
  public num: any = -1;
  public timer = null;
  public doc = document.documentElement;
  private mounted() {
    axios.get("/data.json").then((res) = > {
      this.list = res.data.data;
      this.lists = this.list.slice(0.35);
    });
    listenerScroll(
      this.doc,
      this.$refs.list,
      () = > {
        this.lists = this.lists.concat(this.list.slice(0.35));
      },
      (num) = > {
        this.num = num; }); }}</script>
Copy the code

The problem: Set the style when we need toliThe upper Settings cannot be givenaSet if givenaAfter the height is set, it will not be displayedaThe problem then arises when counting the number of extra bars, as shown in the figureTo prevent the user from dragging the scrollbar too quickly, add an anti-shake function and finally remove event listeners.

public debounce(fn: any, wait: number): any {
    let timeout: any = null;
    return function () {
      if(timeout ! =null) clearTimeout(timeout);
      timeout = setTimeout(fn, wait);
    };
}
Copy the code

The source code is available on github: github.com/clown-Jack/…

conclusion

Review the above thought, in fact, infinite rolling is also simple, is can think of this idea, if not that it is certainly a fantasy, there are also a lot of deficiencies in this place need to improve, welcome to leave a message to discuss and give advice, after all, the water here is very deep, careless shoes wet.

The last

Welcome to pay attention to the author’s wechat public number: the front-end briefing will be regularly updated some dry goods.