Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money

Project implementation based on NuxtJS 2.x construction

Intersection Observer API for MDN Web Docs

  • 1.new IntersectionObserver()Instantiate a global_observer, eachDOMThe node adds itself_observerIs used hereVueTo implement)
  • 2. When someoneDOMThe node enters the window to collect theDOMIs stored in a global arraydotArr, and then cancel theDOMThe observation of
  • 3, fromdotArrUpload data from
    • Run timer, check every N seconds ifdotArrIf you have data, report it;
    • If in N seconds,dotArrIs greater than a certain amount of datamaxNumDon’t wait for the timer
  • 4, do not leak and do not repeatedly report data, the user leaves the edge of the data processing in front of the page
    • Browser environment:dotArrSave a copy of it at the same timelocalStorageIf the user is really in the interval of N seconds, and the data is not enough to report the maximum amountmaxNumLeave the page, then this batch of data will wait for the user next time to enter the page, directly fromlocalStorageTo upload. Of course, if the user never visits the page again or clears the browser cache, a little data loss is acceptable.

Exposure to monitor

  1. createintersection-observer.jsfile
// Install the intersection-Observer plug-in
npm install intersection-observer --save-dev

// Create the observation file intersection-observer.js
import "intersection-observer";
import axios from "axios";

// Data reporting method, namely network request
const platformExposure = (dotDataArr) = > {
  axios
    .post("/api/xxx/exposure", { para: { list: dotDataArr } })
};

// Throttling time, default is 100ms
IntersectionObserver.prototype.THROTTLE_TIMEOUT = 300;

const localStorage = window.localStorage;

export default class Exposure {
  constructor(maxNum = 200) {
    this.dotDataArr = []; // The DOM node data into the window
    this.maxNum = maxNum;
    this.timeout = 1 * 1000 * 60; // Upload at an interval
    this._timer = 0;
    this._observer = null; // A collection of observers
    this.init(); // The Exposure class is instantiated globally only once
  }

  init() {
    const self = this;
    // init will execute only once, bounding method, upload the remaining data in the browser localStorage
    this.dotFromLocalStorage();

    this._observer = new IntersectionObserver(
      (entries, observer) = > {
        // This is triggered when each product enters the window
        entries.forEach((entry) = > {
          if (entry.isIntersecting) {
            // Clear the current timer
            clearTimeout(self._timer);
            
      
// const ctm = entry.target.attributes['data-dot'].value const dataset = entry.target.dataset; const ctm = { platform_id: dataset.id, // Product ID This parameter is mandatory }; // Collect data into the data array to be reported self.dotDataArr.push(ctm); // Unobserve the DOM node after collecting data self._observer.unobserve(entry.target); // Upload directly when the number exceeds a certain threshold if (self.dotDataArr.length >= self.maxNum) { self.dot(); } else { // Otherwise, cache directly self.storeIntoLocalstorage(self.dotDataArr); if (self.dotDataArr.length > 0) { // If there is no new CTM, it will automatically click n seconds later self._timer = window.setTimeout(() = >{ self.dot(); }, self.timeout); }}}}); }, {root: null.// Specify the root directory, which triggers the monitor callback when the target element is displayed within the element. The default value is null, which is the browser window rootMargin: "0px".// Set the border area of the root element threshold: 0.5.// The number or number array controls the threshold above which the target element is visible when entering the root element. This threshold triggers the function. You can also use data to make the element return multiple values in different visibility on entry}); }// Each DOM element executes the add method via a globally unique instance of Exposure, adding itself to the observer add(entry) { this._observer && this._observer.observe(entry.el); } // Upload and update the cache dot() { const dotDataArr = this.dotDataArr.splice(0.this.maxNum); platformExposure(dotDataArr); this.storeIntoLocalstorage(this.dotDataArr); } // Cache data storeIntoLocalstorage(dotDataArr) { localStorage.setItem("dotDataArr".JSON.stringify(dotDataArr)); } // Upload data dotFromLocalStorage() { const ctmsStr = JSON.parse(localStorage.getItem("dotDataArr")); if (ctmsStr && ctmsStr.length > 0) { platformExposure(ctmsStr); }}}Copy the code

Exposure instruction

  1. Complete the exposure instruction filedirectives.client.js
import Vue from "vue";
import Exposure from "./intersection-observer";
// exp globally unique instance
const exp = new Exposure();

Vue.directive("exp-dot", {
  bind(el, binding, vnode) {
    // Every item that uses this command automatically adds itself to the observer
    exp.add({ el, val: binding.value });
  },
  update(newValue, oldValue) {
    // Work when the value is updated
    // It can also be called once with the initial value, which can be processed according to the value type
  },
  unbind() {
    // Clean up}});Copy the code
  1. In the configuration filenuxt.config.jsTo introduce instruction filesdirectives.client.js, includingclientThe deputation is valid only on the client
// nuxt.config.js
module.exports = {
  mode: "universal".plugins: [{ src: "~plugins/directives.client.js"}]};Copy the code

Practical use

The core use is V-EXP-dot

<template>
  <div class="mescroll">
    <div class="list-product">
      <div
        class="list-item"
        v-for="(item, index) in listData"
        :key="item.id"
        :item="item"
        :data-id="item.id"
        :data-url="item.url"
        v-exp-dot
      />
    </div>
  </div>
</template>
Copy the code