javascript - 当元素在视口中时开始视差
问题描述
我在一个对多个元素(文本、图像等)具有视差效果的网站上工作。当元素位于视口底部时,我需要启动视差效果。
在这种情况下,元素距离页面顶部 3000 像素,当元素在视口中时,我想将 window.pageYOffset 重置为零(或类似的东西),这种效果是有意义的。
此代码有效但不好,当我更改分隔符高度时,视差效果的起始位置不同。您可以尝试将 css 中的分隔符高度更改为 500px 和 5000px。
有什么更好的解决方案?
谢谢
这是小提琴:https ://jsfiddle.net/you8c6d7/
function parallax(element, delay) {
var start = document.querySelector(element).getBoundingClientRect().top;
var px = window.pageYOffset - (start * 2 + window.innerHeight);
var elClass = document.querySelector(element);
elClass.style.transform = 'translateY(' + '-' + px / delay + 'px' + ')';
};
window.addEventListener('scroll', function() {
parallax('.box', 5);
});
body {
height: 6000px;
margin 0;
}
.box {
background: blue;
width: 300px;
height: 300px;
}
.separator {
height: 500px;
background: grey;
}
<div class="separator"></div>
<div class="box"></div>
解决方案
这是使用Intersection Observer API的片段。
我使用了实验功能 "IntersectionObserver.thresholds",因此IE 不支持。
该脚本观察目标框是否与视口相交,并根据框/视口的比例对其进行变换。有关更多详细信息,请参阅代码中的注释和 JSDoc。
/**
* Creates an IntersectionObserver and starts observing all elements found using the selector.
*
* @param {String} selector: Selector used to find all target elements
* @param {Number[]} threshold: Array of intersection ratios, at which the callback is executed
* @param {Function} callback: Callback executed for each threshold
*/
function observe(selector, threshold, callback) {
const elements = document.querySelectorAll(selector);
const options = {
rootMargin: '0px',
threshold: threshold,
};
const observer = new IntersectionObserver(callback, options);
for (const element of elements) {
observer.observe(element);
}
}
/**
* Creates a CSS translateY value.
*
* @param {Number} ratio: A number between 0 and 1
* @param {String} total: A valid CSS number and unit (10px, 100%, 30vh, …)
* @return {String} The CSS translateY value.
*/
function translateY(ratio, total) {
return `translateY(calc(-${ratio} * ${total})`;
}
/**
* Callback executed for the box elements
*
* @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
*
* @param {IntersectionObserverEntry[]} entries: Intersection Observer Entries
* @param {IntersectionObserver} observer: Intersection Observer
*/
function boxParallax(entries, observer) {
for (const entry of entries) {
if (entry.isIntersecting) {
entry.target.style.transform = translateY(entry.intersectionRatio, '20%');
}
}
}
/**
* Create one threshold for each intersection ratio.
*
* @return {Number[]}
*/
function createThreshold() {
const threshold = [];
for (let i = 0; i <= 1.0; i += 0.01) {
threshold.push(i);
}
return threshold;
}
const threshold = createThreshold();
observe('.box', threshold, boxParallax);
body {
height: 6000px;
margin 0;
}
.box {
background: blue;
width: 300px;
height: 300px;
}
.separator {
height: 500px;
background: grey;
}
<div class="separator"></div>
<div class="box"></div>
推荐阅读
- php - 将 PHP geoJSON 数据显示到 Mapbox geoJSON
- css - 模糊模态背后的一切?
- r - 如何在特定列中创建包含 NA 的行的新数据集?
- ios - 有没有简单的方法或技巧在 Xcode 中制作布局?
- mediawiki - MediaWiki 1.35 parsoid 超时尝试使用可视化编辑器
- c# - 不尊重 Flurl 超时
- java - 我需要知道屏幕尺寸和屏幕密度有什么不同
- xamarin.forms - 如何解决“发现无法解决的不同版本的“Microsoft.CSharp”之间的冲突。”
- python - Python 搜索数据框以查找具有特殊字符的列表中的单词。输出不如预期
- node.js - Alexa Skill 不适用于出站 API 调用