Я создаю макет сообщения в блоге, который требует, чтобы некоторые метаданные располагались с одной стороны и оставались на месте при прокрутке контента, используя position: sticky
.
Это работает нормально, но некоторые типы контента растягиваются до ширины 100%, поэтому сталкиваются с метаданными при прокрутке. Я хочу запустить прослушиватель событий в прокрутке, который сравнивает положение обоих и добавляет класс к липкому элементу, давая ему opacity:0
, когда другой проходит над ним.
Это прекрасно работает, когда на странице есть только один элемент полной ширины (.fw
):
window.addEventListener('scroll', function() {
var a = document.querySelector('.postmeta-sticky').getBoundingClientRect(),
b = document.querySelector('.fw').getBoundingClientRect();
if ((b.top <= (a.top + a.height)) && ((b.top + b.height) > a.top)) {
$(".postmeta-wrap").addClass("overlap");
} else {
$(".postmeta-wrap").removeClass("overlap");
}
});
Однако контент поста создается динамически, и на странице может быть более одного .fw
. Поэтому я пытаюсь собрать все экземпляры, используя querySelectorAll
для моей второй переменной, но не могу заставить это работать.
Я так далеко в:
window.addEventListener('scroll', function(){
var a = document.querySelector(".postmeta-sticky").getBoundingClientRect(),
objects = document.querySelectorAll(".fw");
objects.forEach(function(object) {
b = object.getBoundingClientRect();
if ((b.top <= (a.top + a.height)) && ((b.top + b.height) > a.top)) {
$(".postmeta-wrap").addClass("overlap");
} else {
$(".postmeta-wrap").removeClass("overlap");
}
});
});
Но это просто не работает. Несомненно, я сделал очевидную ошибку или упущение.
Первый экземпляр работает только на месте: https://hba.matmartin.studio/henry-v-donmar-warehouse/
Упрощенный код: https://codepen.io/MMS_/pen/VwQvvpm
С благодарностью всем, кто может помочь.
jQuery(document).ready(function($) {
window.addEventListener('scroll', function() {
var a = document.querySelector(".sticky-content").getBoundingClientRect(),
objects = document.querySelectorAll(".fw");
objects.forEach(function(object) {
b = object.getBoundingClientRect();
if ((b.top <= (a.top + a.height)) && ((b.top + b.height) > a.top)) {
$(".sticky-wrap").addClass("overlap");
} else {
$(".sticky-wrap").removeClass("overlap");
}
});
});
});
.content {
box-sizing: border-box;
position: relative;
}
.sticky-wrap {
position: absolute;
height: 100%;
width: 33%;
z-index: 0;
}
.sticky-wrap.overlap {
opacity: 0;
}
.sticky-content {
position: sticky;
top: 0;
left: 0;
width: 100%;
height: 112px;
padding: 24px 0;
background: #e9e9e9;
}
.scrolling-content {
width: 100%;
position: relative;
z-index: 1;
}
.scrolling-element {
width: 66%;
height: 160px;
background: #d56d56;
margin: 0 0 48px auto;
}
.scrolling-element.fw {
width: 100%;
background: #9dc9dc;
opacity: 0.5;
}
.page-head {
width: 100%;
height: 72px;
background: #F6F6F6;
}
.page-end {
width: 100%;
height: 480px;
background: #383838;
}
<div class = "page-head"></div>
<div class = "content">
<div class = "sticky-wrap">
<div class = "sticky-content">
<ul>
<li>This info</li>
<li>sticks around</li>
<li>for a bit</li>
</ul>
</div>
</div>
<div class = "scrolling-content">
<div class = "scrolling-element"></div>
<div class = "scrolling-element fw"></div>
<div class = "scrolling-element"></div>
<div class = "scrolling-element fw"></div>
<div class = "scrolling-element"></div>
<div class = "scrolling-element"></div>
</div>
</div>
<div class = "page-end"></div>
<script src = "https://code.jquery.com/jquery-1.12.3.js" integrity = "sha256-1XMpEtA4eKXNNpXcJ1pmMPs8JV+nwLdEqwiJeCQEkyc = " crossorigin = "anonymous"></script>
Это отличный вопрос. Ответ в том, что это предел моих знаний, и я не знаю ничего лучшего. Я очень открыт для любых предложений по улучшению.
Каждый раз в цикле вы добавляете или удаляете класс overlap
из одних и тех же элементов. Таким образом, окончательный результат будет только от последней итерации цикла. Может быть, вы имели в виду $(object).find(".postmeta-wrap")
, чтобы он менял только класс чего-то в текущем элементе .fw
?
ох – спасибо @Barmar. куда бы я вставил это, точно?
Вместо $(".postmeta-wrap")
. Разве вы не понимаете, что это выбирает элементы все с классом, а не что-либо, связанное с итерацией?
Я думаю, что мы сталкиваемся с тем фактом, что я этого не понимаю, как указал @isherwood. Я только что обновил codepen, как вы предлагаете, но без желаемого эффекта.
Я думаю, что Бармар что-то задумал. Я продолжу свой комментарий, указав на некоторые вещи, которые могут помочь: 1) вам не нужна функция document.ready вокруг вашей функции прокрутки. По сути, они делают то же самое здесь. 2) Вы используете древнюю версию jQuery. Скорее всего, вы сможете без проблем обновиться до версии 3.x.
спасибо — обе эти вещи теперь настраиваются в codepen, и, как вы подозревали, все осталось по-прежнему. я начинаю понимать точку зрения Бармара, но, если я не ошибаюсь, чтобы это редактирование сработало, целевой элемент должен быть внутри $object
, верно? что это не так. на странице есть только один экземпляр цели.
Код ниже должен обеспечить поведение, которое вы ищете. Проблема заключалась в том, что более поздние элементы .fw
в списке обновляли видимость метаэлемента.
Я изменил цикл на формат for...of
и добавил разрыв, чтобы остановить цикл, когда он скрыт, и сделал небольшой рефакторинг.
Надеюсь, это сработает!
window.addEventListener('scroll', function(){
var sticky = document.querySelector(".sticky-content");
var a = sticky.getBoundingClientRect();
var objects = document.querySelectorAll(".fw");
for (object of objects) {
b = object.getBoundingClientRect();
if ((b.top <= (a.top + a.height)) && ((b.top + b.height) > a.top)) {
sticky.parentNode.classList.add("overlap");
break;
} else {
sticky.parentNode.classList.remove("overlap");
}
}
});
Не по теме: почему вы отбрасываете кусочки jQuery в то, что в основном представляет собой простой блок кода JavaScript? Это не нужно и путает вещи. См. youmightnotneedjquery.com.