Take commodities for example
Requirement
- Report more than half of the items in the line when they appear in the window
- Fast sliding past products do not report
- In the sliding process, if a line of goods has not disappeared in the field of view (more than half), it cannot be reported repeatedly
- Products that slide out of view need to be reported again when they slide into view again
Analysis
The following information is required
- Height of the line where the product is rowHeight (fixed value)
- The height of the visible area of the product content height (semi fixed value, regardless of browser resize)
- Height of the viewing area from the top of the window headheight (fixed value)
- Scrolling height of content (related to scroll event, considering that no escalation is triggered when the scrolling is fast, throttle is required)
Realization
/** * Rolling event handling * @param {number} headHeight content Height of area from top * @param {number} rowHeight Height of each line * @returns {Function} */ export function handleScroll(headHeight, rowHeight) { let lastActive = [] let deactived = [] /** * @param {number} contentTop top value of area * @return {Array} Currently active rows */ return function(contentTop) { let topDiff = contentTop - headHeight // Height of visible area let visibleHeight = window.innerHeight - (topDiff <= 0 ? headHeight : contentTop) /** * The number of lines that can be displayed currently * If you need to report when you are half exposed, use rounding */ let rowCount = Math.round(visibleHeight / rowHeight) /** * Get the currently displayed subscript */ let index = topDiff > 0 ? 0 : Math.round(-topDiff / rowHeight) let _active = Array.from({ length: rowCount }).reduce( (pre, cur, i) => pre.concat(index + i), [] ) /** * Previously reported but not disappeared from the screen * Reports that have been reported before and disappear from the screen */ let active = _active.filter( v => !lastActive.includes(v) || deactived.includes(v) ) /** * Collect inactive lines and only roll up elements. The lines under active are in inactive status. Because they are related to the total number of lines (whether the total number of goods is known or not does not affect the reporting), unnecessary work will be added, so no consideration is given here */ deactived = Array.from({ length: index }).map((val, i) => i) /** * Last active line to avoid repeated escalation */ lastActive = [].concat(deactived).concat(_active) return { lastActive, active, deactived } } }
Icon
Use
let target = document.getElementById('wrapper') let onScroll = handleScroll(100, 420) let _scroll = _.throttle(function(){ let row = onScroll(target.getBoundingClientRect().y) // At this time, row.active is the subscript of the row to be reported. Active may be an empty array ... }, 1000) target.addEventListener('scroll', _scroll)