## 相交简介 相交,也可以简单把它叫做重叠。如果两个矩形有重叠的区域,那么它们就是相交的。就像下面这样: ![什么是相交](什么是相交.svg) ### 为什么要判断相交? 因为至少可以做以下事情: - **惰性加载:** 当图片元素进入到浏览器窗口内时才加载 - **实现无限滚动:** 当页面底部元素出现时,继续加载更多内容 - **计算广告展现量:** 广告都没有出现,广告是不是白打了? - **按需呈现动画:** 当用户滚动到某一区域时,呈现某个动画 ### 判断相交的传统做法 在没有 IntersectionObserver 的时候,人们通常监听窗口滚动(scroll)事件,并调用某元素的`Element.getBoundingClientRect()`方法来获取 它当前相对于浏览器窗口的坐标信息。但是这种做法有一个非常明显的缺点:窗口滚动事件发生得非常频繁,大量计算,势必会造成浏览器性能问题。 ### IntersectionObserver 的引入 IntersectionObserver 自 HTML5 引入。 它提供了一种以异步方式来观察一个元素的相交性。 ## IntersectionObserver 的使用 ### 创建对象 这个 API 的使用非常简单。 创建一个 IntersectionObserver 对象: ```js var observer = new IntersectionObserver(callback, options); ``` 参数`callback`是一个回调函数,当元素的相交性发生变化时,这个函数会被回调。 而`options`参数则可以用于指定跟哪个元素进行相交判断,相交到哪种程度了进行回调。 ### 观察对象 它有以下几个常用方法: #### `observe()` 观察元素 以下代码观察一个img是否进入浏览器窗口: ```js observer.observe(img); ``` #### `unobserve()` 取消观察元素 以下代码取消观察一个img元素 ```js observer.unobserve(img); ``` ### 回调函数 回调函数长下面这样: ```js function(entries, observer) { } ``` `entries`是一个`Intersection​Observer​Entry`类型的数组,每当有元素的相交性发生变化时,这个类型包含该元素的相交有关的数据。 `observer`是前面创建的观察者。 ### Intersection​Observer​Entry 它有以下几个常用属性: - **intersection​Ratio** 相交比例。刚开始相交是0%,相交一半是50%,完全进入则是100% - **isIntersecting** 是否正在相交。`intersection​Ratio != 0` 即正在相交。(后来增加的属性) - **target** 被观察的元素。 ```js function(entries, observer) { entries.forEach(entry => { if(entry.isIntersecting) { console.log("元素相交"); } else { console.log("元素不相交"); } }); } ``` ### options 选项 (暂无) ## 实例:惰性图片加载 我刚刚在我的博客程序中[实现了惰性图片加载](https://github.com/movsb/taoblog/commit/fc675b4062848dcb58b3cc8526f46fd51b8dc175), 所以我今天就拿这个图片惰性加载来作为实例。 ### 前提:对 img 的修改 为了惰性加载图片,当然不能把 img 的 src 直接设置成图片地址,不然浏览器直接就显示了。而一般是放在`data-src`属性中,或增加`lazy-load`类。 ```html ``` ### 找到所有需要惰性加载的图片 ```js var images = document.querySelectorAll('img[data-src]'); ``` ### 对它们进行相交观察 ```js var observer = new IntersectionObserver(onIntersection); images.forEach(img => { observer.observe(img); }); ``` ### 回调处理 ```js // 回调函数 function onIntersection(entries, observer) { entries.forEach(entry => { // 表示正在相交,即:已经出现 if(entry.intersectionRatio != 0) { let img = entry.target; let src = setSrc(img); // 设置后就可以取消观察这个img了 observer.unobserve(img); console.log("Lazy loading", src); } }); } // 用于设置 img 的 src 为 data-src function setSrc(img) { let src = img.getAttribute('data-src'); img.setAttribute('src', src); return src; } ``` ### 效果展示 注意我是设置到出现 50% 时自动加载图片。缓慢滚动以查看效果! ## 其它 `IntersectionObserver`虽然是一个出现了几年的API,但还并没有被浏览器或平台完全实现(主流浏览器都已实现),所以,酌情使用。 `intersection​Ratio` 比 `isIntersecting` 出现得早,所以优先使用。`isIntersecting = intersection​Ratio != 0`。 总之:作好兼容处理。 ## 参考 - [MDN: Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) - [Five Techniques to Lazy Load Images for Website Performance](https://www.sitepoint.com/five-techniques-lazy-load-images-website-performance/) - [阮一峰:IntersectionObserver API 使用教程](http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html) - [Find if two rectangles overlap](https://www.geeksforgeeks.org/find-two-rectangles-overlap/) - [TaoBlog: feat: lazy loading images ](https://github.com/movsb/taoblog/commit/fc675b4062848dcb58b3cc8526f46fd51b8dc175#diff-7d10113993e8fe5e8da956762da18d88) - [Can I use: IntersectionObserver ?](https://caniuse.com/#search=IntersectionObserver)