1 | import Taro from '@tarojs/api';
|
2 | import { findDOM } from '../../utils/index.js';
|
3 |
|
4 | class TaroH5IntersectionObserver {
|
5 |
|
6 | get container() {
|
7 | const container = (this._component !== null
|
8 | ? (findDOM(this._component) || document)
|
9 | : document);
|
10 | return container;
|
11 | }
|
12 | constructor(component, options = {}) {
|
13 |
|
14 | this._options = {
|
15 | thresholds: [0],
|
16 | initialRatio: 0,
|
17 | observeAll: false
|
18 | };
|
19 |
|
20 | this._listeners = [];
|
21 |
|
22 | this._rootMargin = {};
|
23 |
|
24 | this._isInited = false;
|
25 | this._component = component;
|
26 | Object.assign(this._options, options);
|
27 | }
|
28 | createInst() {
|
29 |
|
30 | this.disconnect();
|
31 | const { left = 0, top = 0, bottom = 0, right = 0 } = this._rootMargin;
|
32 | return new IntersectionObserver(entries => {
|
33 | entries.forEach(entry => {
|
34 | const _callback = this._getCallbackByElement(entry.target);
|
35 | const result = {
|
36 | boundingClientRect: entry.boundingClientRect,
|
37 | intersectionRatio: entry.intersectionRatio,
|
38 | intersectionRect: entry.intersectionRect,
|
39 | relativeRect: entry.rootBounds || { left: 0, right: 0, top: 0, bottom: 0 },
|
40 |
|
41 | time: Date.now(),
|
42 | };
|
43 |
|
44 | if (!this._isInited && this._options.initialRatio <= Math.min.apply(Math, this._options.thresholds)) {
|
45 |
|
46 | return;
|
47 | }
|
48 | _callback && _callback.call(this, result);
|
49 | });
|
50 | this._isInited = true;
|
51 | }, {
|
52 | root: this._root,
|
53 | rootMargin: [`${top}px`, `${right}px`, `${bottom}px`, `${left}px`].join(' '),
|
54 | threshold: this._options.thresholds
|
55 | });
|
56 | }
|
57 | disconnect() {
|
58 | if (this._observerInst) {
|
59 | let listener;
|
60 | while ((listener = this._listeners.pop())) {
|
61 | this._observerInst.unobserve(listener.element);
|
62 | }
|
63 | this._observerInst.disconnect();
|
64 | }
|
65 | }
|
66 | observe(targetSelector, callback) {
|
67 |
|
68 | if (this._listeners.length)
|
69 | return;
|
70 |
|
71 | if (!this._observerInst) {
|
72 | console.warn('Intersection observer will be ignored because no relative nodes are found.');
|
73 | return;
|
74 | }
|
75 | const nodeList = this._options.observeAll
|
76 | ? this.container.querySelectorAll(targetSelector)
|
77 | : [this.container.querySelector(targetSelector)];
|
78 | Taro.nextTick(() => {
|
79 | nodeList.forEach(element => {
|
80 | if (!element)
|
81 | return;
|
82 | this._observerInst.observe(element);
|
83 | this._listeners.push({ element, callback });
|
84 | });
|
85 | });
|
86 | }
|
87 | relativeTo(selector, margins) {
|
88 |
|
89 | if (this._listeners.length) {
|
90 | console.error('Relative nodes cannot be added after "observe" call in IntersectionObserver');
|
91 | return this;
|
92 | }
|
93 | this._root = this.container.querySelector(selector) || null;
|
94 | if (margins) {
|
95 | this._rootMargin = margins;
|
96 | }
|
97 | this._observerInst = this.createInst();
|
98 | return this;
|
99 | }
|
100 | relativeToViewport(margins) {
|
101 | return this.relativeTo('.taro_page', margins);
|
102 | }
|
103 | _getCallbackByElement(element) {
|
104 | const listener = this._listeners.find(listener => listener.element === element);
|
105 | return listener ? listener.callback : null;
|
106 | }
|
107 | }
|
108 |
|
109 | export { TaroH5IntersectionObserver };
|
110 |
|