List browsing buried point reporting solution implementation
Buried point introduction
What are data burying points
The so-called “buried point” is a method of data collection, a term in the field of data collection. It refers to the technology and implementation process of capturing, processing and sending according to specific user behavior or time. At present, common front-end buried point methods are mainly divided into three kinds: code buried point, visual buried point and traceless buried point, and the list of buried point to share the solution is an application scenario of code buried point.
Application scenarios
Recently in the process of project development, encountered such a buried point requirements: flow of goods falls to add buried browsing data points, when the user browse scroll through commodity flow and waterfall, report all complete in equipment commodity list data buried point on the window, when once again to browse to the current commodity, filter has been reported after the goods continue to report the data points.
Implementation scheme
For this product demand, we should not consider the realization of its significance, but first research feasible implementation plan, of course, this is only my personal little complaints, please do not mind, the following into the topic, this demand, the final determination of the implementation plan is as follows:
- Listen for page scroll pauses
- Calculates the list of items that stay in the window
- Report filtered commodity list data
1. Monitor screen pauses
We all know that browsers don’t provide events to listen for scrolling pauses, so how do you do that? The method is as simple as listening for a screen-scrolling event to execute a callback that throttles the actual screen-stopping callback.
However, there is a drawback to listening for screen scroll throttling, which is still reported when the user stays scrolling and switches the page window before throttling time is up. Therefore, it is necessary to simultaneously listen to the page hide event trigger the timer to clear the screen stay callback, and listen to the page display event trigger the timer to recreate the screen callback, so as to ensure the accuracy of data reporting.
Since the project is realized based on Vue, in order to bury the reusability of the code of the point scheme, we adopt the logical reuse method of mixin, and the code is shown as follows:
// page-event.js
import Vue from 'vue';
export default Vue.extend({
methods: {
/** * page display hook * Switching from another window to the current page triggers execution *@param {function} callback
*/
onShow(callback) {
const handler = () = > {
if (document.visibilityState === 'visible') { callback && callback(); }};document.addEventListener('visibilitychange', handler);
this.$once('hook:beforeDestroy'.() = > {
document.removeEventListener('visibilitychange', handler);
});
},
/** * page hiding hook * Switching from the current page to another page triggers execution *@param {function} callback
*/
onHide(callback) {
const handler = () = > {
if (document.visibilityState === 'hidden') { callback && callback(); }};document.addEventListener('visibilitychange', handler);
this.$once('hook:beforeDestroy'.() = > {
document.removeEventListener('visibilitychange', handler);
});
},
/** * page scroll hook * trigger execution when sending page scroll *@param {function} callback
*/
onPageScroll(callback) {
const handler = () = > {
callback && callback();
}
document.addEventListener('scroll', handler);
this.$once('hook:beforeDestroy'.() = > {
document.removeEventListener('scroll', handler); }); ,}}});// stay-screen.js
import Vue from 'vue';
import pageEvent from './page-event';
export default Vue.extend({
mixins: [
pageEvent
],
data() {
return {
stayStarted: false.stayShow: false.stayPaused: false.stayTimeoutId: null.stayTime: 1000.stayScreenCallback: null.// The screen pauses to perform the callback}},created() {
this.onShow(this.stayOnShow);
this.onHide(this.stayOnHide);
this.onPageScroll(this.stayOnScroll);
},
methods: {
/** * Start page scroll after calculating the page linger ** stayTime after the time elapsed, trigger pause execute callback * default start does not trigger the screen linger calculation */
startStay() {
if (!this.stayStarted) {
return;
}
this.stayTimeoutId = setTimeout(() = > {
this.stayTimeoutId = null;
if (this.stayScreenCallback) {
this.stayScreenCallback(); }},this.stayTime);
},
/** Pause the calculation page to stay */
pauseStay() {
if (!this.stayStarted) {
return;
}
this.stayPaused = true;
this.clearStay();
},
/** continue to calculate the page stays */
continueStay() {
if (!this.stayStarted || !this.stayShow) {
return;
}
if (this.stayPaused) {
this.stayPaused = false;
this.startStay(); }},/** recalculate the page stay */
restartStay() {
if (!this.stayStarted || !this.stayShow) {
return;
}
this.clearStay();
this.startStay();
},
/** Clear the computing page to stay */
clearStay() {
if (this.stayTimeoutId) {
clearTimeout(this.stayTimeoutId);
this.stayTimeoutId = null; }},/** * Initializes the calculation stop * executes the trigger to start the calculation page stop */
stayInit() {
if (!this.stayStarted) {
this.stayStarted = true;
this.stayShow = true;
this.startStay(); }},/** Scroll to refresh the calculation page and stay */
stayOnScroll() {
this.restartStay();
},
/** continue counting while the page is displayed */
stayOnShow() {
this.stayShow = true;
this.continueStay();
},
/** Pause the calculation while the page is hidden */
stayOnHide() {
this.stayShow = false;
this.pauseStay(); }}});Copy the code
2. Calculate the list of items that stay in the window
Calculation for the commodity information inside the window, we need to use an API method Element. GetBoundingClientRect, this method returns the Element size and relative position of the viewport. This allows us to go through all the list elements and calculate whether or not they exist in the view window. However, the frequency of screen scrolling events is too frequent, and the calculation scheme that matches the element information after each screen stop seems not ideal. There is too much unnecessary double-counting.
Optimization scheme: calculate the index of the first list element and the last list element on the viewport by dichotomy, intercept the required list element through the index and then report, the code is as follows:
// Some code
{
/** * Gets the viewport list element *@params* bottomHeight Height at the bottom of the viewport * Gap gap between list elements */
getScreenItems({ topHeight, bottomHeight, gap }) {
const firstIndex = this.searchScreenFirstItem(topHeight, gap);
const lastIndex = this.searchScreenLastItem(bottomHeight, gap);
console.log(firstIndex, lastIndex);
const screenItems = this.list.slice(firstIndex, lastIndex + 1);
return screenItems;
},
/** * gets the first list element */ in the viewport
searchScreenFirstItem(topHeight, gap) {
topHeight = topHeight || 0;
gap = gap || 0;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
const screeenTop = topHeight;
// List element ref
const listItems = this.$refs.listItem;
if (Array.isArray(listItems)) {
let low = 0;
let high = listItems.length - 1;
let mid;
while (low <= high) {
mid = Math.floor((low + high) / 2);
const itemRect = listItems[mid].getBoundingClientRect();
if (itemRect.top + itemRect.height + gap < screeenTop) {
low = mid + 1;
} else if (itemRect.top > screeenTop) {
high = mid - 1;
} else {
// Returns the index of the next element between the height of the item element
// Returns the current element index when the screen window size is smaller than the element height
return itemRect.height < clientHeight ? mid + 1: mid; }}}return 0;
},
/** * gets the last list element */ in the viewport
searchScreenLastItem(bottomHeight, gap) {
bottomHeight = bottomHeight || 0;
gap = gap || 0;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
const screenBottom = clientHeight - bottomHeight;
const listItems = this.$refs.listItem;
let len = 0;
if (Array.isArray(listItems)) {
len = listItems.length;
let low = 0;
let high = len - 1;
let mid;
while (low <= high) {
mid = Math.floor((low + high) / 2);
const itemRect = listItems[mid].getBoundingClientRect();
if (itemRect.top + itemRect.height < screenBottom) {
low = mid + 1;
} else if (itemRect.top - gap > screenBottom) {
high = mid - 1;
} else {
// Returns the index of the last element between the height of the item element
// Returns the current element index when the screen window size is smaller than the element height
return itemRect.height < clientHeight ? mid - 1: mid; }}}return len - 1; }}Copy the code
3. Report buried data
With the previous steps, there is little to be said for burying data in the report, other than listening for screen stops, filtering out the required list elements, and then burying the list data in the report.
The final overall code implementation can be viewed in my Github warehouse. If you think the above scheme can help you, please give me a star. Thank you very much 🙏!!