Intersection Observer 针对不同窗口大小进行微调
Posted
技术标签:
【中文标题】Intersection Observer 针对不同窗口大小进行微调【英文标题】:Intersection Observer fine tuning for different window sizes 【发布时间】:2021-02-11 05:08:22 【问题描述】:这是我目前的代码:
const mediaInViewport = document.querySelectorAll('.media');
const links = Array.from(document.querySelectorAll('.link'));
let actLink = links[0];
document.body.addEventListener('click', (event) =>
if (event.target.tagName === 'a')
actLink.classList.remove('active');
actLink = links.find(link => event.target.href === link.href)
actLink.classList.add('active');
, false)
observer = new IntersectionObserver((entries, observer) =>
entries.forEach((entry) =>
if (entry.target && entry.isIntersecting)
const closestParent = entry.target.closest('section');
if (closestParent)
actLink.classList.remove('active');
actLink = links.find(link =>
link.href.slice(link.href.lastIndexOf('#')) === `#$closestParent.id`
)
actLink.classList.add('active');
);
,
threshold: 0
);
window.addEventListener('DOMContentLoaded', () =>
setTimeout( // Wait for images to fully load
() =>
mediaInViewport.forEach((item) =>
observer.observe(item);
);
, 1000);
);
*
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 30px;
text-decoration: none;
color: inherit;
body
display: flex;
cursor: default;
#left,
#right
width: 50%;
height: 100vh;
overflow-y: scroll;
scroll-behavior: smooth;
#left
background-color: rgb(220, 220, 220);
#right
background-color: rgb(200, 200, 200);
.media
padding: 10px;
padding-bottom: 0;
.media:nth-last-child(1)
margin-bottom: 10px;
img
display: block;
width: 100%;
.link
cursor: pointer;
.active
background-color: black;
color: white;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="left">
<a class="link active" href="#landscape">Landscapes</a>
<a class="link" href="#cats">Cats</a>
<a class="link" href="#beer">Beer</a>
<a class="link" href="#food">Food</a>
</div>
<div id="right">
<section id="landscape">
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
</section>
<section id="cats">
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
</section>
<section id="beer">
<article class="media beer">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/89/Craft_Beer_at_the_Taedonggang_Microbrewery_No._3_%2812329931855%29.jpg">
</article>
</section>
<section id="food">
<article class="media food">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Good_Food_Display_-_NCI_Visuals_Online.jpg/1200px-Good_Food_Display_-_NCI_Visuals_Online.jpg">
</article>
</section>
</div>
观察功能应该适用于所有窗口大小。目前,如果窗口大小稍大一些,例如“啤酒”链接如果您单击它或滚动太不敏感,则不会收到 .active
类。
有没有办法解决这个问题?
需要如下规则:
-
始终只有最后观察到的对象会触发
.active
类。
但是:如果在某一点有不同的可观察对象可见
(例如点击链接“啤酒”后),然后“最
占主导地位的“一个(未被切断且最存在的那个)应该
触发.active
类。
我会非常感谢您的帮助!
【问题讨论】:
【参考方案1】:const mediaInViewport = Array.from(document.querySelectorAll('.media'));
const sections = Array.from(document.querySelector('#right').children);
const links = Array.from(document.querySelectorAll('.link'));
let actLink = links[0];
let actSection = null;
let targetLink = null;
let targetSection = null;
document.body.addEventListener('click', (event) =>
if (event.target.tagName === 'A')
event.preventDefault();
targetLink = event.target;
targetSection = sections.find(section => section.id === targetLink.href.slice(targetLink.href.lastIndexOf('#')+1))
location.hash = targetLink.href.slice(targetLink.href.lastIndexOf('#'));
actLink.classList.remove('active');
actLink = links.find(l => event.target.href === l.href)
actLink.classList.add('active');
, false)
observer = new IntersectionObserver((entries, observer) =>
entries.forEach((entry) =>
if (entry.target && entry.isIntersecting)
const closestParent = entry.target.closest('section');
if (closestParent)
actLink.classList.remove('active');
if (!targetLink)
actLink = links.find(link =>
link.href.slice(link.href.lastIndexOf('#')) === `#$closestParent.id`
)
else
if (closestParent === targetSection)
targetLink = null
actSection = sections.find(section => section.id === actLink.href.slice(actLink.href.lastIndexOf('#')))
actLink.classList.add('active');
);
,
threshold: 0.3
);
window.addEventListener('DOMContentLoaded', () =>
setTimeout( // Wait for images to fully load
() =>
mediaInViewport.forEach((item) =>
observer.observe(item);
);
, 1000);
);
*
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 30px;
body
display: flex;
cursor: default;
#left,
#right
width: 50%;
height: 100vh;
overflow-y: scroll;
scroll-behavior: smooth;
#left
background-color: rgb(220, 220, 220);
#right
background-color: rgb(200, 200, 200);
.media
padding: 10px;
padding-bottom: 0;
.media:nth-last-child(1)
margin-bottom: 10px;
img
display: block;
width: 100%;
.link:active
cursor: pointer;
a:target
background-color: black;
color: white;
a
text-decoration: none;
color: inherit;
section:target
background-color: black;
color: white;
.active
background-color: black;
color: white;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="left">
<a class="link active" href="#landscape">Landscapes</a>
<a class="link" href="#cats">Cats</a>
<a class="link" href="#beer">Beer</a>
<a class="link" href="#food">Food</a>
</div>
<div id="right">
<section id="landscape">
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
</section>
<section id="cats">
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
</section>
<section id="beer">
<article class="media beer">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/89/Craft_Beer_at_the_Taedonggang_Microbrewery_No._3_%2812329931855%29.jpg">
</article>
</section>
<section id="food">
<article class="media food">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Good_Food_Display_-_NCI_Visuals_Online.jpg/1200px-Good_Food_Display_-_NCI_Visuals_Online.jpg">
</article>
</section>
</div>
【讨论】:
塔安克斯!我觉得现在好多了。但是,如果窗口大小处于类似全景的方向,并且无论如何图像都会被截断,那么只有在设置“阈值:0”时它才能正常工作。在所有其他情况下,“阈值:0”会破坏函数。你有解决这个问题的想法吗? 不,我还没有……但我会考虑的。 也许带有媒体查询的 css 会有所帮助,,, 您也可以根据方向更改阈值***.com/questions/4917664/… 我有一些改进代码的想法,但我会先检查一下以上是关于Intersection Observer 针对不同窗口大小进行微调的主要内容,如果未能解决你的问题,请参考以下文章
跟踪元素可视?试试Intersection Observer