摘要:構(gòu)造函數(shù)調(diào)用時(shí),需要給它傳一個(gè)回調(diào)函數(shù)。當(dāng)監(jiān)聽的元素進(jìn)入可視區(qū)域或者從可視區(qū)域離開時(shí),回調(diào)函數(shù)就會被調(diào)用。構(gòu)造函數(shù)的返回值是一個(gè)觀察器實(shí)例。它是一個(gè)數(shù)組,每個(gè)成員都是一個(gè)門檻值,默認(rèn)為,即交叉比例達(dá)到時(shí)觸發(fā)回調(diào)函數(shù)。
IntersectionObserve這個(gè)API,可能知道的人并不多(我也是最近才知道...),這個(gè)API可以很方便的監(jiān)聽元素是否進(jìn)入了可視區(qū)域。
testbox
上圖代碼中,.box元素目前并不在可視區(qū)域(viewport)內(nèi),如何監(jiān)聽它進(jìn)入可視區(qū)域內(nèi)?
傳統(tǒng)做法是:監(jiān)聽scroll事件,實(shí)時(shí)計(jì)算.box距離viewport的top值:
const box = document.querySelector(".box"); const viewHeight = document.documentElement.clientHeight; window.addEventListener("scroll", () => { const top = box.getBoundingClientRect().top; if (top < viewHeight) { console.log("進(jìn)入可視區(qū)域"); } });
然而scroll事件會頻繁觸發(fā),因此我們還需要手動(dòng)節(jié)流。
使用IntersectionObserve就非常方便了:
const box = document.querySelector(".box"); const intersectionObserver = new IntersectionObserver((entries) => { entries.forEach((item) => { if (item.isIntersecting) { console.log("進(jìn)入可視區(qū)域"); } }) }); intersectionObserver.observe(box);
IntersectionObserver API是異步的,不隨著目標(biāo)元素的滾動(dòng)同步觸發(fā),所以不會有性能問題。
IntersectionObserver構(gòu)造函數(shù)const io = new IntersectionObserver((entries) => { console.log(entries); }); io.observe(dom);
調(diào)用IntersectionObserver時(shí),需要給它傳一個(gè)回調(diào)函數(shù)。當(dāng)監(jiān)聽的dom元素進(jìn)入可視區(qū)域或者從可視區(qū)域離開時(shí),回調(diào)函數(shù)就會被調(diào)用。
注意: 第一次調(diào)用new IntersectionObserver時(shí),callback函數(shù)會先調(diào)用一次,即使元素未進(jìn)入可視區(qū)域。
構(gòu)造函數(shù)的返回值是一個(gè)觀察器實(shí)例。實(shí)例的observe方法可以指定觀察哪個(gè) DOM 節(jié)點(diǎn)。
// 開始觀察 io.observe(document.getElementById("example")); // 停止觀察 io.unobserve(element); // 關(guān)閉觀察器 io.disconnect();IntersectionObserverEntry對象
callback函數(shù)被調(diào)用時(shí),會傳給它一個(gè)數(shù)組,這個(gè)數(shù)組里的每個(gè)對象就是當(dāng)前進(jìn)入可視區(qū)域或者離開可視區(qū)域的對象(IntersectionObserverEntry對象)
這個(gè)對象有很多屬性,其中最常用的屬性是:
target: 被觀察的目標(biāo)元素,是一個(gè) DOM 節(jié)點(diǎn)對象
isIntersecting: 是否進(jìn)入可視區(qū)域
intersectionRatio: 相交區(qū)域和目標(biāo)元素的比例值,進(jìn)入可視區(qū)域,值大于0,否則等于0
options調(diào)用IntersectionObserver時(shí),除了傳一個(gè)回調(diào)函數(shù),還可以傳入一個(gè)option對象,配置如下屬性:
threshold: 決定了什么時(shí)候觸發(fā)回調(diào)函數(shù)。它是一個(gè)數(shù)組,每個(gè)成員都是一個(gè)門檻值,默認(rèn)為[0],即交叉比例(intersectionRatio)達(dá)到0時(shí)觸發(fā)回調(diào)函數(shù)。用戶可以自定義這個(gè)數(shù)組。比如,[0, 0.25, 0.5, 0.75, 1]就表示當(dāng)目標(biāo)元素 0%、25%、50%、75%、100% 可見時(shí),會觸發(fā)回調(diào)函數(shù)。
root: 用于觀察的根元素,默認(rèn)是瀏覽器的視口,也可以指定具體元素,指定元素的時(shí)候用于觀察的元素必須是指定元素的子元素
rootMargin: 用來擴(kuò)大或者縮小視窗的的大小,使用css的定義方法,10px 10px 30px 20px表示top、right、bottom 和 left的值
const io = new IntersectionObserver((entries) => { console.log(entries); }, { threshold: [0, 0.5], root: document.querySelector(".container"), rootMargin: "10px 10px 30px 20px", });懶加載
圖片懶加載的原理就是:給img標(biāo)簽一個(gè)自定義屬性,用來記錄真正的圖片地址。默認(rèn)img標(biāo)簽只加載一個(gè)占位符。當(dāng)圖片進(jìn)入可視區(qū)域時(shí),再把img的src屬性更換成真正的圖片地址。
const intersectionObserver = new IntersectionObserver((entries) => { entries.forEach((item) => { if (item.isIntersecting) { item.target.src = item.target.dataset.src; // 替換成功后,停止觀察該dom intersectionObserver.unobserve(item.target); } }) }, { rootMargin: "150px 0px" // 提前150px進(jìn)入可視區(qū)域時(shí)就加載圖片,提高用戶體驗(yàn) }); const imgs = document.querySelectorAll("[data-src]"); imgs.forEach((item) => { intersectionObserver.observe(item) });打點(diǎn)上報(bào)
前端頁面經(jīng)常有上報(bào)數(shù)據(jù)的需求,比如統(tǒng)計(jì)頁面上的某些元素是否被用戶查看,點(diǎn)擊。這時(shí),我們就可以封裝一個(gè)Log組件,用于當(dāng)元素進(jìn)入可視區(qū)域時(shí),就上報(bào)數(shù)據(jù)。
以React為例,我們希望:被Log組件包裹的元素,進(jìn)入可視區(qū)域后,就向后臺發(fā)送{ appid: 1234, type: "news"}數(shù)據(jù)
console.log("log")} > console.log("news")}>其他內(nèi)容
import React, { Component } from "react"; import PropTypes from "prop-types"; class Log extends Component { static propTypes = { log: PropTypes.object }; constructor(props) { super(props); this.io = null; this.ref = React.createRef(); } componentDidMount() { this.io = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { console.log("進(jìn)入可視區(qū)域,將要發(fā)送log數(shù)據(jù)", this.props.log); sendLog(this.props.log); this.io.disconnect(); } } ); this.io.observe(this.ref.current); } componentWillUnmount() { this.io && this.io.disconnect(); } render() { // 把log屬性去掉,否則log屬性也會渲染在div上 // const { log, ...props } = this.props; return (兼容性{this.props.children}) } } export default Log
safari并不支持該API,因此為了兼容主流瀏覽器,我們需要引入polyfill
intersection-observer
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/102240.html
摘要:請考生務(wù)必妥善保管個(gè)人網(wǎng)報(bào)用戶名密碼及準(zhǔn)考證居民身份證等證件,避免泄露丟失造成損失。自主劃線院校會在月陸續(xù)公布初試成績基本要求。鎖定時(shí)間到達(dá)后,如招生單位未明確受理意見,鎖定解除,考生可繼續(xù)填報(bào)其他志愿。 ...
摘要:是基于圖畫,可視化數(shù)據(jù)工具。如圖更多的配置可以看官方的配置項(xiàng)手冊,每一項(xiàng)都有很詳細(xì)的說明。參考本地創(chuàng)建了文件用于儲存數(shù)據(jù)然后異步請求。因?yàn)槭褂玫?,所以引入了一個(gè)。使用的非常好用。 Echarts.js是基于canvas 圖畫,可視化數(shù)據(jù)工具。 Echarts官方案例 官網(wǎng)下載Echarts 然后引入官網(wǎng)下載Echarts.js ECharts 入門示例--柱...
摘要:附上個(gè)人簡歷小程序圖,做得怎么樣,大家可以微信掃描體驗(yàn)下,多指教下。小程序開發(fā)資源匯總小程序開發(fā)框架在里面找了找,和比較火,畢竟是騰訊官方的開源,故我選擇了。 >>>點(diǎn)擊獲取更多文章
閱讀 4215·2021-10-08 10:04
閱讀 3172·2021-08-11 11:20
閱讀 2931·2021-07-25 21:37
閱讀 2762·2019-08-30 12:44
閱讀 2412·2019-08-30 11:12
閱讀 1388·2019-08-26 13:45
閱讀 2441·2019-08-26 11:53
閱讀 3138·2019-08-26 11:32