当元素在视口中时触发自定义事件-JavaScript



我需要链接这两个代码,这样当;isElementInViewport;函数返回true以触发";inviewport";事件:

let inViewportEvent = document.createEvent("Event");
inViewportEvent.initEvent("inviewport", true, true);
document.addEventListener("inviewport", (e) => {
console.log(`${e.target} in viewport!`)
}, false);
document.dispatchEvent(inViewportEvent);

该功能用于检测元素是否在视口中:

const isElementInViewport = el => {
let rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}

我们必须使用CustomEvent构造函数来创建一个新的custom event,然后使用dispatchEvent来触发它…

const inViewportCustomEvent = new CustomEvent('inviewport', {
detail: { 
/* put the data to be carried here*/
}
});
document.dispatchEvent(inViewportCustomEvent);

插图

const isElementInViewport = (el) => {
let rect = el.getBoundingClientRect();
// console.log(rect);
const isIn = (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
console.log('[isElementInViewport]', isIn, {
top: rect.top,
right: rect.right,
left: rect.left,
bottom: rect.bottom,
innerHeight: window.innerHeight,
clientHeight: document.documentElement.clientHeight,
innerWidth: window.innerWidth,
clientWidth: document.documentElement.clientWidth
});
return isIn;
};
const observer_callback = (entries, observer) => {
entries.filter(entry => isElementInViewport(entry.target))
.forEach(entry => {
console.log("We got something");
const inViewportCustomEvent = new CustomEvent('inviewport', {
detail: {
target: entry
/* put the data to be carried here*/
}
});
document.dispatchEvent(inViewportCustomEvent);
});
};
function create_observer() {
let options = {
root: document,
rootMargin: "5px"
};
return new IntersectionObserver(observer_callback, options);
}
const outermost = document.querySelector("#outermost");
const fill_counter = document.querySelector("#fill_counter");
const filler = document.querySelector("#filler");
const fill_clearer = document.querySelector("#fill_clearer");
const highlighted_index = document.querySelector("#highlighted_index");
function fill_squares(num_squares) {
outermost.append(...new Array(num_squares).fill(0).map((_, index) => create_square(index)));
function create_square(index) {
const divEle = document.createElement("div");
divEle.setAttribute("data-index", index);
divEle.classList.add("square");
divEle.onclick = (event) => {
event.target.classList.toggle("square");
event.target.classList.toggle("highlighted_square");
}
return divEle;
}
}
function highlight_square(index) {
const selected_square = outermost.querySelector(`[data-index="${index}"]`);
if (selected_square) {
if (!selected_square.classList.contains("highlighted_square")) {
selected_square.classList.toggle("square");
selected_square.classList.toggle("highlighted_square");
}
}
}
function highlight_squares(indexes) {
if (indexes && indexes.length) {
indexes.forEach(index => highlight_square(index));
}
}
function clear_children(parentElement) {
var e = parentElement;
var first = e.firstElementChild;
while (first) {
first.remove();
first = e.firstElementChild;
}
}
resetter.onclick = (event) => {
fill_counter.value = outermost.getAttribute("data-fill-count");
highlighted_index.value = +outermost.getAttribute("data-highlight-index");
reset();
}
filler.onclick = (event) => {
reset();
}
highlighter.onclick = (event) => {
const highlightedIndex = +highlighted_index.value < +event.target.min ? +event.target.value : +highlighted_index.value;
if (!isNaN(highlightedIndex)) {
highlight_square(highlightedIndex);
}
}

fill_counter.onchange = (event) => {
let current_value = +event.target.value;
if (!isNaN(current_value)) {
if (current_value < +event.target.min) {
event.target.value = +event.target.min;
}
}
}
highlighted_index.onchange = (event) => {
let current_value = +event.target.value;
if (!isNaN(current_value)) {
if (current_value < +event.target.min) {
event.target.value = +event.target.min;
}
if (+event.target.value === +event.target.min) {
event.target.value = +event.target.min;
}
}
}
function reset() {
clear_children(outermost);
fill_squares(+fill_counter.value);
}
function setup_listener() {
document.addEventListener("inviewport", (e) => {
console.log(`${e.detail.target} in viewport!`)
}, false);
}
reset();
highlight_squares([19, 50, 35]);
setup_listener();
const observer = create_observer();
outermost.querySelectorAll('.highlighted_square').forEach(square => observer.observe(square));
.input_region {
margin: 5px;
}
.input_region label {
display: inline-block;
}
.action_input {
padding: 10px;
}
.highlighted_square {
background: yellow
}
.num_input {
height: 30px;
width: 50px;
padding: 5px;
}
.square {
background: magenta
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr));
grid-auto-rows: 1fr;
}
.grid::before {
content: '';
width: 0;
padding-bottom: 100%;
grid-row: 1 / 1;
grid-column: 1 / 1;
}
.grid>*:first-child {
grid-row: 1 / 1;
grid-column: 1 / 1;
}

/* Just to make the grid visible */
.grid>* {
// background: rgba(0, 0, 0, 0.1);
border: 1px white solid;
}
<section>
<div class="input_region">
<input class="num_input" id="fill_counter" type="number" value="1000" min="10" />
<button id="filler" class="action_input">FILL</button>
</div>
<div class="input_region">
<input class="num_input" id="highlighted_index" type="number" value="10" min="0" />
<button id="highlighter" class="action_input">HIGHLIGHT</button>
</div>
<div class="input_region">
<button class="action_input" id="resetter">RESET</button>
</div>
</section>
<section>
<div id="outermost" class="grid" data-fill-count="1000" data-highlight-index="100"></div>
</section>

最新更新