sal原始碼解析-輕量級的滾動動畫庫

sihai發表於2019-01-07

sal是以效能為中心,輕量級的滾動動畫庫

1.前言

sal(滾動擴充套件庫)為滾動動畫提供高效能和輕量級的解決方案。sal採用Intersection Observer,在視口中,它在檢查元素方面提供了很好的效能。強烈建議優先閱讀阮大神的IntersectionObserver API 使用教程文章,瞭解基本IntersectionObserver的使用

本篇讀後感分為五部分,分別為前言、使用、解析、demo、總結,五部分互不相連可根據需要分開看。

1前言為介紹、2使用為庫的使用、3解析為原始碼的解析、4demo是抽取原始碼的核心實現的小demo,5總結為吹水,學以致用。

建議跟著原始碼結合本文閱讀,這樣更加容易理解!

  1. IntersectionObserver API 使用教程
  2. sal
  3. sal解析的Github地址

2.使用

<
!DOCTYPE html>
<
html lang="en">
<
body>
<
div data-sal="slide-up" data-sal-delay="300" data-sal-easing="ease-out-bounce" >
<
/div>
<
/body>
<
script>
sal({
once: false
});
<
/script>
<
/html>
複製程式碼

當頁面開始滾動時,為標籤新增了data-sal屬性的標籤就會隨著滾動展示動畫效果。

data-sal有三種選項:

  • data-sal-duration – 動畫時長;
  • data-sal-delay – 動畫延遲時間;
  • data-sal-easing – 動畫速度曲線。

sal函式接收三個引數:

  • threshold– 目標元素的可見比例
  • once – 只執行一次動畫
  • disable – 禁用動畫

3.解析

庫的原理是通過IntersectionObserverapi,觀察目標元素的可見比例,通過新增或者移除class來啟動動畫

import './sal.scss';
/** * 預設選項 */let options = {
rootMargin: '0% 50%', threshold: 0.5, animateClassName: 'sal-animate', disabledClassName: 'sal-disabled', selector: '[data-sal]', once: true, disabled: false,
};
/** * 私有 */let elements = [];
let intersectionObserver = null;
/** * 為元素新增class啟動動畫 * @param {Node
} element */
const animate = element =>
( element.classList.add(options.animateClassName));
/** * 通過移除class來反轉啟動動畫 * @param {Node
} element */
const reverse = element =>
( element.classList.remove(options.animateClassName));
/** * 元素是否已經啟動過動畫 * @param {Node
} element */
const isAnimated = element =>
( element.classList.contains(options.animateClassName));
/** * 為元素移除disabledClassName來啟用動畫 */const enableAnimations = () =>
{
document.body.classList.remove(options.disabledClassName);

};
/** * 通過新增class來禁用動畫 */const disableAnimations = () =>
{
document.body.classList.add(options.disabledClassName);

};
/** * 是否禁用動畫 * @return {Boolean
} */
const isDisabled = () =>
( options.disabled || ( (typeof options.disabled === 'function') &
&
options.disabled() ));
/** * IntersectionObserver的回撥函式 * @param {Array<
IntersectionObserverEntry>

} entries * @param {IntersectionObserver
} observer */
const onIntersection = (entries, observer) =>
{
entries.forEach((entry) =>
{
if (entry.intersectionRatio >
= options.threshold) {
// 元素的可見比例大於配置的可見比例,啟動動畫 animate(entry.target);
if (options.once) {
observer.unobserve(entry.target);

}
} else if (!options.once) {
// 否則,啟動反轉動畫 reverse(entry.target);

}
});

};
/** * 禁用sal */const disable = () =>
{
disableAnimations();
intersectionObserver.disconnect();
intersectionObserver = null;

};
/** * 啟動 */const enable = () =>
{
enableAnimations();
/** * 設定對觀察元素變化後的行為函式 * intersectionObserver:觀察者 * onIntersection: 觀察到變化的行為函式 */ intersectionObserver = new IntersectionObserver(onIntersection, {
rootMargin: options.rootMargin, threshold: options.threshold,
});
// 獲取觀察元素 elements = [].filter.call( document.querySelectorAll(options.selector), element =>
!isAnimated(element, options.animateClassName), );
// 為觀察元素設定觀察者,當變化後觸發行為函式 elements.forEach(element =>
intersectionObserver.observe(element));

};
/** * Init * @param {Object
} settings * @return {Object
} public API */
const init = (settings = options) =>
{
// 初始化配置 if (settings !== options) {
options = {
...options, ...settings,
};

} // 判斷瀏覽器是否存在IntersectionObserver if (!window.IntersectionObserver) {
disableAnimations();
throw Error(` Your browser does not support IntersectionObserver! Get a polyfill from here: https://github.com/w3c/IntersectionObserver/tree/master/polyfill `);

} // 開始和結束動畫 if (!isDisabled()) {
enable();

} else {
disableAnimations();

} return {
elements, disable, enable,
};

};
export default init;
複製程式碼

4.demo

通過實現阮大神的兩個例子來上手IntersectionObserver,也是sal的原理

4.1 惰性載入(lazy load)

當滾動到一定位置的時候,再載入對應的圖片

<
!DOCTYPE html>
<
html lang="en">
<
head>
<
meta charset="UTF-8">
<
meta name="viewport" content="width=device-width, initial-scale=1.0">
<
meta http-equiv="X-UA-Compatible" content="ie=edge">
<
title>
lazyLoad<
/title>
<
style>
html, body{
height: 100%;
padding: 0;
margin: 0;

} .block{
width: 100%;
height: 700px;

} .red{
background-color: red;

} .green{
background-color: green;

} .yellow{
background-color: yellow;

} img{
width: 100%;

}
<
/style>
<
/head>
<
body>
<
div class="block red">
<
/div>
<
div class="block green">
<
/div>
<
div class="block yellow">
<
/div>
<
/body>
<
script>
var threshold = 0.3var onIntersection = (changes, observer) =>
{
changes.forEach(function(change) {
var container = change.target if (change.intersectionRatio >
threshold) {
var img = new Image() img.src = './fafa.jpeg' container.append(img) observer.unobserve(container)
}
})
}var observer = new IntersectionObserver(onIntersection, {threshold
})document.querySelectorAll('.block').forEach(element =>
observer.observe(element))
<
/script>
<
/html>
複製程式碼

4.2 無限滾動(infinite scroll)

觀察列表底部元素載入更多,每當達到設定的可見比例時,就載入資料到列表中

<
!DOCTYPE html>
<
html lang="en">
<
head>
<
meta charset="UTF-8">
<
meta name="viewport" content="width=device-width, initial-scale=1.0">
<
meta http-equiv="X-UA-Compatible" content="ie=edge">
<
title>
lazyLoad<
/title>
<
style>
html, body{
height: 100%;
padding: 0;
margin: 0;

} h1{
border-bottom: 1px solid #000;

}
<
/style>
<
/head>
<
body>
<
div class="wrap">
<
div class="list">
<
/div>
<
div class="bottom">
載入更多<
/div>
<
/div>
<
/body>
<
script>
var num = 0var skip = 10var threshold = 0.9function load(){
var list = document.querySelector('.list') var fragment = document.createDocumentFragment();
Array(skip).fill().forEach((v, i) =>
{
var dom = document.createElement('h1') num += 1 dom.innerText = num fragment.append(dom)
}) list.append(fragment)
}var onIntersection = (changes, observer) =>
{
changes.forEach(function(change) {
if (change.intersectionRatio >
threshold) load()
})
}var observer = new IntersectionObserver(onIntersection, {threshold
})observer.observe(document.querySelector('.bottom'))
<
/script>
<
/html>
複製程式碼

5.總結

sal這個庫其實主要是對IntersectionObserver的應用,程式碼簡單僅僅只有一百多行,但由於IntersectionObserver還只是個實驗階段的api(雖然chrome支援了),在實際專案中運用的機會不是太大,但是對它抱有期待。就如無限滾動的例子,如果不使用IntersectionObserver的話,就得監聽瀏覽器滾動事件,獲取列表高度、視窗高度和滾動高度來計算是否滾動到底部,必要情況下還需要加上防抖動來優化使用者體驗,所以IntersectionObserver還是省去很多步驟的,看好!

轉眼就到了2019年了,要堅持分享輸出!

sal原始碼解析-輕量級的滾動動畫庫

來源:https://juejin.im/post/5c32a758e51d4551e13b6491

相關文章