Скрытая точка внешних данных экспозиции — команда Intersection Observer+vue

Vue.js

1. Введение

В продуктах электронной коммерции (вы можете открыть свои приложения Taobao, Tmall и Jingdong), скрывая данные о воздействии продукта, вы можете изменить поведение пользователя и привычки взаимодействия, чтобы оптимизировать рекомендации и алгоритмы поиска и взаимодействия, и, наконец, цель, конечно, увеличить покупательную способность пользователей. 

Экспозиция: Продукт появляется перед пользователем, то есть в окне браузера, что можно охарактеризовать как экспозицию.

Два самых простых способа

Можно использовать оба метода, ноgetBoundingClientRectЭтот API вызовет переформатирование страницы, а неправильное использование может легко привести к проблемам с производительностью. 

На основе этого браузер специально создал[Intersection Observer API - Web API | MDN], чтобы иметь дело с деталями, связанными с производительностью, чтобы разработчики заботились только о бизнес-логике



Во-вторых, INTERSECTION OBSERVER API

Весь план точки воздействия основан на[Intersection Observer API — Справочник по интерфейсу веб-API | MDN]

Этот API все еще относительно новый, что касается проблем с совместимостью.[IntersectionObserver/polyfill· w3c]решить по существуgetBoundingClientRectРассчитать расположение, как это реализовать можно в его исходниках


В-третьих, идея захоронения данных

  1. new IntersectionObserver() Примеры глобального_observer, каждый продукт DOM добавляет себя_observerСписок наблюдения (это будет реализовано с помощью директив Vue)
  2. Когда DOM продукта входит в окно, собирайте информацию о продукте и сохраняйте ее в глобальном массиве.dotArr, а затем отменить наблюдение за товарным DOM
  3. отdotArrСравнительно просто взять данные из
  • Запускаем таймер, проверяем его каждые N секунд и сообщаем напрямую, если в dotArr есть данные;
  • Если в течение N секундdotArrОбъем данных превышает определенное количествоmaxNum, не дожидаясь таймера, сообщать обо всем напрямую
  • Управлять несложно, но сложно не пропускать и не сообщать данные повторно, а обрабатывать граничные данные до того, как пользователь покинет страницу
      • Среда браузера:dotArrВ то же время существуетlocalStorage, синхронно обновить данные (добавить или очистить после отчета), если пользователь действительно находится в интервале N секунд, а данных недостаточно, чтобы сообщить максимальное количествоmaxNumКогда левая страница, то эти данные в следующий раз, когда пользователь на другой странице, непосредственно изlocalStorageКонечно, если пользователь больше никогда не заходит на страницу и не очищает кеш браузера, эта небольшая потеря данных приемлема. 
      • Среда веб-просмотра на стороне клиента: зарегистрируйте событие закрытия веб-просмотра (требуется поддержка детской обуви на стороне клиента) и уничтожьте все перед выходом.


    В-четвертых, реализация кода

    1. Инкапсулируйте класс экспозиции

    // polyfill
    import 'intersection-observer';
    // 自行封装数据上报方法,其实就是网络请求
    import { DotData } from './DotData'
    
    // 可以把节流的时间调大一点,默认是100ms
    IntersectionObserver.prototype['THROTTLE_TIMEOUT'] = 300;
    
    export default class Exposure {
      dotDataArr: Array<string>;
      maxNum: number;
      // _observer可以理解为观察者的集合吧
      _observer;
      _timer: number;
    
      constructor(maxNum = 20) {
        // 当前收集的  尚未上报的数据  也就是已经进入视窗的DOM节点的数据
        this.dotDataArr = [];
        this.maxNum = maxNum;
        this._timer = 0;
        // 全局只会实例化一次Exposure类,init方法也只会执行一次
        this.init();
      }
    
      init() {
        const self = this;
        // init只会执行一次,所以这两边界处理方法放这就行
        // 把浏览器localStorage里面的剩余数据打完
        this.dotFromLocalStorage();
        // 注册客户端webview的关闭生命钩子事件
        this.beforeLeaveWebview();
    
        this._observer = new IntersectionObserver(function (entries, observer) {
          entries.forEach(entry => {
            // 这段逻辑,是每一个商品进入视窗时都会触发的
            if (entry.isIntersecting) {
              // 清楚当前定时器
              clearTimeout(self._timer);
              // 我这里是直接把商品相关的数据直接放DOM上面了  比如 <div {...什么id  class style等属性} :data-dot="渲染商品流时自行加上自身属性" ></div>
              const ctm = entry.target.attributes['data-dot'].value;
              // 把收集到的数据添加进待上报的数据数组中
              self.dotDataArr.push(ctm);
              // 收集到该商品的数据后,取消对该商品DOM的观察
              self._observer.unobserve(entry.target);
              // 超过一定数量打点,打完点会删除这一批
              if (self.dotDataArr.length >= self.maxNum) {
                self.dot();
              } else {
                self.storeIntoLocalstorage(self.dotDataArr);
                if (self.dotDataArr.length > 0) {
                  //,只要有新的ctm进来  接下来如果没增加  自动2秒后打
                  self._timer = window.setTimeout(function () {
                    self.dot();
                  }, 2000)
                }
              }
            }
          })
        }, {
            root: null,
            rootMargin: "0px",
            threshold: 0.5 // 不一定非得全部露出来  这个阈值可以小一点点
          });
    
      }
    
      // 每个商品都会会通过全局唯一的Exposure的实例来执行该add方法,将自己添加进观察者中
      add(entry) {
        this._observer && this._observer.observe(entry.el)
      }
    
      dot() {
        // 同时删除这批打点的ctms
        const dotDataArr = this.dotDataArr.splice(0, this.maxNum);
        DotData(dotDataArr);
        // 打完点,也顺便更新一下localStorage
        this.storeIntoLocalstorage(this.dotDataArr);
      }
    
      storeIntoLocalstorage(dotDataArr) {
        // 。。。 存进localStorage中,具体什么格式的字符串自行定义就好
      }
    
      dotFromLocalStorage() {
        const ctmsStr = window.localStorage.getItem('dotDataArr');
        if (ctmsStr) {
          // 。。。如果有数据,就上报打点
        }
      }
    
      beforeLeaveWebview() {
        let win: any = window;
        // 自行跟客户端童鞋约定该钩子的实现就好
        injectEvent("webviewWillDisappear", () => {
          if (this.dotDataArr.length > 0) {
            DotData(this.dotDataArr);
          }
        })
      }
    }

    2. Создание экземпляра Vue + инструкции по упаковке

    [Пользовательская директива — Vue.js]

    // 入口JS文件 main.js
    // 引入Exposure类
    // exp就是那个全局唯一的实例
    const exp = new Exposure();
    
    // vue封装一个指令,每个使用了该指令的商品都会自动add自身进观察者中
    Vue.directive('exp-dot', {
        bind(el, binding, vnode) {
            exp.add({el: el, val: binding.value})
        }
    })

    3. Использование товаров

    Просто используйте команду для каждого элемента во время цикла

     :data-dot="item.dotData"это данные, которые мы собираемся собрать

    <div 
        v-exp-dot 
        v-for="item in list" 
        :key="item.id" 
        class="" 
        :data-dot="item.dotData"
    >
      // ... 
    </div>

    В первоначальном плане мы намерены каждый раз вручную инициировать наблюдение за партией продуктов, например, подтягивание и загрузка для создания партии новых продуктов, ручная интерактивная загрузка партии новых продуктов и т. д., и непосредственно управлять экземпляр наблюдателяосматриватьЭта новая партия

    Позже выяснилось, что завязка с бизнес-логикой слишком тяжелая, и не обязательно все товары на странице отрисовываются массивом в послушном порядке, также могут быть разные ресурсные биты и разные причины их появления. , лучше пусть каждый продукт срабатывает самнаблюдать


    5. Еще

    Спасибо за ваше терпение, чтобы увидеть здесь, и я надеюсь, что вы узнаете что-то!

    Мне нравится делать записи в процессе обучения. Я делюсь некоторыми своими накоплениями и размышлениями о начальном этапе. Я надеюсь общаться с вами и добиваться прогресса. Дополнительные статьи см.[блог амандакелаке на Github]


    Ссылаться на

    [Тест статистики экспозиции на основе IntersectionObserver | xgfe]

    [Анализ причин и решения для потери RBI перед разгрузкой]