Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IntersectionObserver #10

Open
justjavac opened this issue Jul 6, 2017 · 7 comments
Open

IntersectionObserver #10

justjavac opened this issue Jul 6, 2017 · 7 comments
Labels

Comments

@justjavac
Copy link
Owner

简介

  • 你想跟踪 DOM 树里的一个元素,当它进入可视区域时得到通知。
  • 你想实现延迟加载图片功能
  • 你需要知道用户是否真的在看一个广告 banner。

你可以通过绑定 scroll 事件或者用一个周期性的定时器,然后在回调函数中调用元素的 getBoundingClientRect() 获取元素位置实现这个功能。但是,这种实现方式性能极差,因为每次调用 getBoundingClientRect() 都会强制浏览器 重新计算整个页面的布局 ,可能给你的网站造成相当大的闪烁。

IntersectionObserver 就是为此而生的,它可以检测一个元素是否可见,IntersectionObserver 能让你知道一个被观测的元素什么时候进入或离开浏览器的视口。

兼容性

  • Chrome 51+(发布于 2016-05-25)
  • Android 5+ (Chrome 56 发布于 2017-02-06)
  • Edge 15 (2017-04-11)
  • iOS 不支持

Polyfill

WICG 提供了一个 polyfill

Chrome
Firefox
Safari
6+
Edge
Internet Explorer
7+
Opera
Android
4.4+

实用程度

★★★★

相关链接

@justjavac justjavac mentioned this issue Jul 6, 2017
@liudianliang
Copy link

不支持IOS是不是意味着不能做移动端了?

@justjavac
Copy link
Owner Author

有 polyfill

@jiangtao
Copy link

写了个demo, 比如 我要在滚动到离图片的位置多出300距离做操作, 就得在图片相邻的地方插入一个元素,或者在优化下用一个元素,但是增加了计算量 ,absolute且物理位置隐藏, 然后才能原有的效果

相比较于,requestIdleCallback 做调度也能做不少事情。

不过这个api在一些需求上 确实很好使。

@Tao-Quixote
Copy link

摘录自IntersectionObserver’s Coming into View

IntersectionObservers deliver their data asynchronously, and your callback code will run in the main thread. Additionally, the spec actually says that IntersectionObserver implementations should use requestIdleCallback(). This means that the call to your provided callback is low priority and will be made by the browser during idle time. This is a conscious design decision.

从规范来看,IntersectionObserver的实现应该使用requestIdleCallback,那就是说IntersectionObserver的优先级比较低,低优先级在什么情况下会造成什么问题吗?

@justjavac
Copy link
Owner Author

IntersectionObservers 的回调是异步执行的,但是也提供了同步调用的方法 IntersectionObserver.takeRecords()

每一个 IntersectionObserverEntry 都是 [[QueuedEntries]]。当观察到交互动作发生时,回调函数并不会立即执行,而是在空闲时期使用 requestIdleCallback 来异步执行回调函数,而且还规定了最大的延迟时间是 100 毫秒(???),相当于我么你的代码 1-100 毫秒内执行。

我们可以看一下 polyfill 的实现:

To enable polling for all instance, set a value for POLL_INTERVAL on the IntersectionObserver prototype:

IntersectionObserver.prototype.POLL_INTERVAL = 100; // Time in milliseconds.

Enabling polling for individual instance:

To enable polling on only specific instances, set a POLL_INTERVAL value on the instance itself:

var io = new IntersectionObserver(callback);
io.POLL_INTERVAL = 100; // Time in milliseconds.
io.observe(someTargetElement);

Note: the POLL_INTERVAL property must be set prior to calling the .observe method, or the default configuration will be used.

如果执行的是紧急任务,不想异步执行,可以调用同步方法 takeRecords()

Intersection Observers Explainer Doc 中有个显示广告的例子:

function visibleTimerCallback(element, observer) {
  delete element.visibleTimeout;
  // Process any pending observations
  processChanges(observer.takeRecords());
  if ('isVisible' in element) {
    delete element.isVisible;
    logImpressionToServer();
    observer.unobserve(element);
  }
}

如果异步的回调先执行了,那么当我们调用同步的 takeRecords() 方法时会返回空数组。同理,如果已经通过 takeRecords() 获取了所有的观察者实例,那么回调函数就不会被执行了。在规范中或者 polyfill 代码已经很清楚了。

综上:

  1. IntersectionObserver 虽然优先级低,但是可以保证肯定会执行
  2. 如果需要立即执行,可以使用同步的 takeRecords() 方法

@justjavac
Copy link
Owner Author

今天在 github trending 看到一个项目:stratiformltd/react-loadable-visibility

A wrapper around react-loadable and loadable-components to load elements that are visible on the page.

react-loadable-visibility 包装了 react-loadable 和 loadable-components,并且使用了
IntersectionObserver 当指定元素进入到 viewport 时加载组件。

参考

@leixus
Copy link

leixus commented Jun 25, 2018

很好的 +111

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants