How to Realize Immersive Video Experience?

  javascript

Immersive video experience

Last week, the younger brother of the product dropped a demand called “Immersive Video Experience”. The general content is that there are dozens of videos in a page. When the user clicks on one of the videos, the video automatically slides to the top of the viewable area of the screen to start playing and pauses other videos. The video will automatically pause after sliding out of the viewable area of the screen.

This requirement has two key technical points:

  1. How do I slide the video to the top of the viewable area of the screen
  2. How to Judge Video Slips Out of Visual Area of Screen

In fact, the two technical points have one thing in common, that is, the absolute position of the element in the page needs to be calculated, that is, the coordinates of the upper left corner of the element relative to the upper left corner of the entire webpage can be calculated in two ways:

1. Recursion

utilizeoffsetTopAndoffsetLeftYou can get the upper left corner of the current element relative to itHTMLElement.offsetParentThe pixel value offset from the left boundary of the node is then reusedHTMLElement.offsetParent
You can get a locating element that points to the nearest containing the element.

If there are no positioned elements, thenoffsetParentFor the most recenttable,table cellOr the root element (in standard modehtml;quirksThe mode isbody)。

Using the above three attributes, write a recursive function to get the absolute position of the current element in the page:

const getElementLeft = element => {
let actualLeft = element.offsetLeft;
let current = element.offsetParent;
while (current !  == null){
actualLeft += current.offsetLeft;
current = current.offsetParent;
}
return actualLeft;
}
const getElementTop = element => {
let actualTop = element.offsetTop;
let current = element.offsetParent;
while (current !  == null){
actualTop += current.offsetTop;
current = current.offsetParent;
}
return actualTop;
}

Note: As in the table and iframe,offsetParentObjects are not necessarily equal to parent containers, so the above functions are not applicable to elements in tables and iframe.

2. Have you heard of getBoundingClientRect?

object.getBoundingClientRect()The return value of contains a set of read-only attributes, including thelefttoprightAndbottom, and of the elementwidthAndheight, the unit is pixels, the specific meaning can be seen in the figure below:

As can be seen from the above figure,getBoundingClientRectThe obtained value is relative to the viewport, not absolute. When scrolling occurs in the viewport area or other scrollable elements, the top and left attribute values will change immediately.

To obtain the attribute value positioned relative to the upper left corner of the entire web page, simply add the current scroll position (throughwindow.scrollXAndwindow.scrollY), so you can get a value that is independent of the current scroll position.

How do I slide the video to the top of the viewable area of the screen?

with a view togetBoundingClientRectThe compatibility of the is good, and the algorithm complexity is low, finally I adoptedgetBoundingClientRectMethod to realize the function of “sliding the video to the top of the visual area of the screen”, use thewindow.scrollTo achieve page scrolling, use thesetTimeoutTo increase the animation during scrolling, the specific function to realize scrolling is as follows:

const autoScroll = (offsetTop, needScrollTop, hasScrollTop) => {
 let _needScrollTop = needScrollTop;  //The distance from the end point during this recursion.
 let _hasScrollTop = hasScrollTop;  //The sum of the distances that have been moved during this recursion.
 const speed = 10;
 setTimeout(() => {
 const dist = needScrollTop > 0
 ?  Math.max(Math.ceil(needScrollTop / speed), 5)
 : Math.min(Math.ceil(needScrollTop / speed), -5);
 _needScrollTop -= dist;
 _hasScrollTop += dist;
 window.scroll(0, offsetTop + _hasScrollTop);
 //If the movement amplitude is less than 10 pixels, move directly, otherwise call recursively to realize animation effect
 if (_needScrollTop > speed || _needScrollTop < -speed) {
 this.__onScroll(offsetTop, _needScrollTop, _hasScrollTop);
 } else {
 window.scroll(0, offsetTop + _hasScrollTop + _needScrollTop);
 }
 }, 1);
 }
 
 const rect = element.getBoundingClientRect();
 
 const offsetTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || window.screenY;
 
 autoScroll(offsetTop, rect.top, 0);

How do you determine if the video has slipped out of the viewable area of the screen?

utilizegetBoundingClientRectThe return value of can also judge the exposure and slide-out of the element in the visible area of the screen, which is triggered at the end of scrolling by monitoring the scrolling event of the page.checkLeaveAndcheckExposeFunction, the specific code is as follows:

//detect sliding out of visual area
 checkLeave() {
 const element = document.querySelector(`[data-action-id="${this.__domId}"]`);
 if (!  element) {
 console.error(`Action: element [data-action-id="${this.__domId}"] not found`);
 return;
 }
 const { top, bottom, left, right } = element.getBoundingClientRect();
 if ((top > getWindowHeight() || bottom < 0
 || left > getWindowWidth() || right < 0)) {
 this.onLeave();  //onLeave function to implement specific business logic
 }
 }
 
 //Detect Real Exposure
 checkExpose() {
 const element = document.querySelector(`[data-action-id="${this.__domId}"]`);
 if (!  element) {
 console.error(`Action: element [data-action-id="${this.__domId}"] not found`);
 return;
 }
 const { top, bottom, left, right } = element.getBoundingClientRect();
 if (Math.max(0, top) <= Math.min(getWindowHeight(), bottom)
 && Math.max(0, left) <= Math.min(getWindowWidth(), right)) {
 this.onExpose();  //onExpose function to implement specific business logic
 }
 }

The two events can be encapsulated into one<Action>When using the two props parameters of the component, only one layer needs to be wrapped around the required elements.<Action>Parent element and pass in a specific callback function.

BTW, say one more word and I will do itdocument.querySelectorThe principle of direct look at the code:

render() {
const { children } = this.props;
return cloneElement(Children.only(children), {
'data-action-id': this.__domId,
});
}

Above.

Author: TNFE No.2 Primary School

Team promotion

TNFE teamFor front-end developers, the latest high-quality content in small programs and web front-end technologies has been compiled. It is updated weekly. Welcome to star, github address:https://github.com/Tnfe/TNFE-Weekly
Welcome to Tencent front-end technology exchange QQ group: 784383520