我是javascript的初学者,我正在尝试使用es6规范构建一些东西。
我想从ScrollMagic重新创建引脚效果,并在向下滚动页面时固定不同的部分。
所以我有这个简单的html标记,标题是一个页脚和3个部分:
<header class="forewords">
<h1>Some text</h1>
</header>
<div class="wrapper">
<section class="project" id="item1">this is section 1</section>
<section class="project" id="item2">this is section 2</section>
<section class="project" id="item3">this is section 3</section>
</div>
<footer class="endings">
<h1>some text</h1>
</footer>
我附上了一些样式来模拟现实情况。
这是javascript逻辑:
获取所有项目:
const projects = Array.from(document.querySelectorAll('.project'));
从顶部和所有项目高度偏移所有项目:
let projectsOffsetTop = projects.map(project => project.offsetTop);
let projectsHeight = projects.map(project => project.offsetHeight);
如果有人调整窗口大小,请创建一个更新值的函数:
function updateProjectsOffsetTop() {
projectsOffsetTop = projects.map(project => project.offsetTop);
projectsHeight = projects.map(project => project.offsetHeight);
};
window.addEventListener('resize', updateProjectsOffsetTop);
如果滚动大于其偏移量,则最后固定该元素。
function pinElement() {
if (window.scrollY >= projectsOffsetTop[1]) {
document.body.style.paddingTop = projectsHeight[1] +'px';
projects[1].classList.add('fixed');
} else {
document.body.style.paddingTop = 0;
projects[1].classList.remove('fixed');
}
};
window.addEventListener('scroll', pinElement);
但我不能让它适用于所有项目元素。即使有for循环。什么是最佳做法?如果可能的话,我想在Vanilla ES6中解决这个问题。
找到完整的js小提琴。
由于
const projects = Array.from(document.querySelectorAll('.project'));
let projectsOffsetTop = projects.map(project => project.offsetTop);
let projectsHeight = projects.map(project => project.offsetHeight);
function updateProjectsOffsetTop() {
projectsOffsetTop = projects.map(project => project.offsetTop);
projectsHeight = projects.map(project => project.offsetHeight);
};
function pinElement() {
if (window.scrollY >= projectsOffsetTop[1]) {
document.body.style.paddingTop = projectsHeight[1] +'px';
projects[1].classList.add('fixed');
} else {
document.body.style.paddingTop = 0;
projects[1].classList.remove('fixed');
}
};
window.addEventListener('resize', updateProjectsOffsetTop);
window.addEventListener('scroll', pinElement);
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
margin: 0;
padding: 0;
}
header, footer {
width: 100%;
padding: 10%;
background-color: grey;
position: relative;
}
.project {
width: 100%;
height: 100vh;
position: relative;
display: flex;
justify-content: center;
align-items: center;
top: 0;
}
#item1 {background-color: yellow;}
#item2 {background-color: blue;}
#item3 {background-color: red;}
.fixed {
position: fixed;
}
<header class="forewords"><h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum soluta ipsam quaerat cupiditate neque, necessitatibus amet nihil perferendis sunt minus! Exercitationem nulla inventore, aut beatae magnam, totam et minus hic.</h1>
</header>
<div class="wrapper">
<section class="project" id="item1">this is section 1</section>
<section class="project" id="item2">this is section 2</section>
<section class="project" id="item3">this is section 3</section>
</div>
<footer class="endings"><h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vel, perferendis ullam totam recusandae sed repellendus cum! Molestiae, aut ut sequi eos quidem nam quo est, ad tempora inventore odit.</h1>
</footer>
答案 0 :(得分:2)
你提供了一个令人惊叹的MCVE,所以非常感谢你花了这么多精力和时间来提出一个很好的问题。好消息是你几乎那里!你的逻辑是合理的,一切都是有道理的。你真正缺少的是:
fixed
类).project
元素的索引您希望在pinElement()
方法中执行以下操作:
projectsOffsetTop
值,但最接近它(以便它将成为我们想要固定的元素).project
元素的索引-1
(即我们没有符合第2点条件的元素),return
并停止执行。1
替换为我们在步骤3中确定的索引。考虑到这一点,这是您稍微重构的pinElement()
方法:
function pinElement() {
// Reset all styles
projects.forEach((project) => {
document.body.style.paddingTop = 0;
project.classList.remove('fixed');
});
// Get the index of the project that is closest to top
const valueClosestToScrollY = Math.max.apply(Math, projectsOffsetTop.filter((offsetTop) => offsetTop <= window.scrollY));
const idx = projectsOffsetTop.indexOf(valueClosestToScrollY);
// If index is not found, we don't do anything
if (idx === -1)
return;
// Otherwise, we set the appropriate styles and classes
if (window.scrollY >= projectsOffsetTop[idx]) {
document.body.style.paddingTop = `${projectsHeight[idx]}px`;
projects[idx].classList.add('fixed');
}
};
有趣的提示:您可以使用模板文字来执行此操作:
document.body.style.paddingTop = `${projectsHeight[idx]}px`;
......而不是:
document.body.style.paddingTop = ${projectsHeight[idx] + 'px';
这是一个概念验证示例:
const projects = Array.from(document.querySelectorAll('.project'));
let projectsOffsetTop = projects.map(project => project.offsetTop);
let projectsHeight = projects.map(project => project.offsetHeight);
function updateProjectsOffsetTop() {
projectsOffsetTop = projects.map(project => project.offsetTop);
projectsHeight = projects.map(project => project.offsetHeight);
};
function pinElement() {
// Reset all styles
projects.forEach((project) => {
document.body.style.paddingTop = 0;
project.classList.remove('fixed');
});
// Get the index of the project that is closest to top
const valueClosestToScrollY = Math.max.apply(Math, projectsOffsetTop.filter((offsetTop) => offsetTop <= window.scrollY));
const idx = projectsOffsetTop.indexOf(valueClosestToScrollY);
// If index is not found, we don't do anything
if (idx === -1)
return;
// Otherwise, we set the appropriate styles and classes
if (window.scrollY >= projectsOffsetTop[idx]) {
document.body.style.paddingTop = `${projectsHeight[idx]}px`;
projects[idx].classList.add('fixed');
}
};
window.addEventListener('resize', updateProjectsOffsetTop);
window.addEventListener('scroll', pinElement);
&#13;
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
margin: 0;
padding: 0;
}
header,
footer {
width: 100%;
padding: 10%;
background-color: grey;
position: relative;
}
.project {
width: 100%;
height: 100vh;
position: relative;
display: flex;
justify-content: center;
align-items: center;
top: 0;
}
#item1 {
background-color: yellow;
}
#item2 {
background-color: blue;
}
#item3 {
background-color: red;
}
.fixed {
position: fixed;
}
&#13;
<header class="forewords">
<h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum soluta ipsam quaerat cupiditate neque, necessitatibus amet nihil perferendis sunt minus! Exercitationem nulla inventore, aut beatae magnam, totam et minus hic.</h1>
</header>
<div class="wrapper">
<section class="project" id="item1">this is section 1</section>
<section class="project" id="item2">this is section 2</section>
<section class="project" id="item3">this is section 3</section>
</div>
<footer class="endings">
<h1>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vel, perferendis ullam totam recusandae sed repellendus cum! Molestiae, aut ut sequi eos quidem nam quo est, ad tempora inventore odit.</h1>
</footer>
&#13;
在旁注中,出于性能原因,您可能希望调查滚动事件的限制/去抖动,以免过度调用pinElement()
。