沉浸式视频体验

上周产品小哥哥丢过来一个需求,名曰:沉浸式视频体验,大致内容是一个页面里有几十个视频,用户点击其中一个视频时,该视频自动滑动到屏幕可视区域的顶部开始播放,并暂停其他视频,该视频滑出屏幕可视区域之后要自动暂停。

这个需求有两个关键的技术点:

  1. 如何将视频滑动到屏幕可视区域的顶部
  2. 如何判断视频滑出了屏幕可视区域

其实这两个技术点有一个共同点,就是需求计算出元素在页面中的绝对位置,也就是指该元素的左上角相对于整张网页左上角的坐标,有两种方法可以计算得到:

1.递归

利用offsetTop和offsetLeft可以取到当前元素左上角相对于其HTMLElement.offsetParent节点的左边界偏移的像素值,然后再利用HTMLElement.offsetParent
可以得到一个指向最近的包含该元素的定位元素。

如果没有定位的元素,则offsetParent为最近的table,table cell或根元素(标准模式下为htmlquirks模式下为body)。

利用以上三个属性,写一个递归函数就可以得到当前元素在页面中的绝对位置了:

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;
}

注意:由于在表格和iframe中,offsetParent对象未必等于父容器,所以上面的函数对于表格和iframe中的元素不适用。

2. 你听说过getBoundingClientRect吗?

object.getBoundingClientRect()的返回值包含了一组只读属性,包括该元素相对于视口左上角位置的lefttoprightbottom,以及元素的widthheight,单位为像素,具体含义可参见下图:

从上图可以看出,getBoundingClientRect得到的值是相对于视口的,而不是绝对的,当视口区域或其他可滚动元素内发生滚动操作时,top和left属性值就会随之立即发生变化。

要获得相对于整个网页左上角定位的属性值,只要给top、left属性值加上当前的滚动位置(通过window.scrollXwindow.scrollY),这样就可以获取与当前的滚动位置无关的值。

如何将视频滑动到屏幕可视区域的顶部?

考虑到getBoundingClientRect的兼容性较好,且算法复杂度较低,最终我采用了getBoundingClientRect方法来实现“将视频滑动到屏幕可视区域的顶部”的功能,使用window.scroll来实现页面滚动,使用setTimeout增加滚动时的动画,具体实现滚动的函数如下:

const autoScroll = (offsetTop, needScrollTop, hasScrollTop) => {let _needScrollTop = needScrollTop; // 本次递归时,离终点的距离let _hasScrollTop = hasScrollTop; // 本次递归时,已经移动的距离总和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 (_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);

如何判断视频滑出了屏幕可视区域?

利用getBoundingClientRect的返回值同样可以判断元素在屏幕可视区域的曝光和滑出,通过监听页面的滚动事件,在滚动结束时,触发checkLeavecheckExpose函数,具体代码如下:

// 检测滑出可视区域
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函数中实现具体业务逻辑}
}// 检测真实曝光
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函数中实现具体业务逻辑}
}

可以将这两个事件封装成了一个<Action>组件的两个props参数,使用时只需要在需要的元素外包一层<Action>父元素,并传入特定的回调函数即可。

BTW,多说一句我实现document.querySelector的原理,直接看代码:

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

以上。

作者:TNFE 二小

团队推广

TNFE团队为前端开发人员整理出了小程序以及web前端技术领域的最新优质内容,每周更新✨,欢迎star,github地址:https://github.com/Tnfe/TNFE-Weekly
欢迎加入腾讯前端技术交流QQ群:784383520

来源:https://segmentfault.com/a/1190000018657822

如何实现沉浸式视频体验?相关推荐

  1. Lytro发布光场影片,让你感受真正的沉浸式视频体验

    在这部影片中,你可以进行六个自由度的全方位观影. 说到Lytro,很多人对这家公司的印象还停留在做光场相机上,在今年4月份的时候,Lytro表示要放弃以"先拍照后聚焦"为特色的光场 ...

  2. 与金山云的樊博士聊了聊AV1算法优化以及如何提升沉浸式视频的沉浸感

    讲师介绍 樊鸿飞,金山云高级研发总监,北京大学计算机科学与技术专业博士,负责视频云的VR.视频编码.人工智能等技术线研发,近年来主要从事沉浸式视频.视频编码.图像处理.计算机视觉方向上的研究与技术落地 ...

  3. 沉浸式视频技术应用与挑战

    正文字数:4766  阅读时长:7分钟 随着5G时代的到来,低延时.超高清视频将成为未来几年内视频发展的主流趋势之一,沉浸式视频或将迎来其爆发期.金山云 CDN及视频云产品中心高级技术总监 蔡媛在线上 ...

  4. “云”溪笔谈 | 走完过渡期“沉浸式视频云”时代来临

    先科普一个"冷知识":2018年8月,在线视频领域用户使用时长首次超越社交领域,成为全网第一大领域. 全球CDN的使用情况同样佐证了这一点:2017年开始,视频云流量市场始终保持7 ...

  5. 文旅融合助力沉浸式夜游体验项目的发展

    2022上半年,受国内疫情形势影响,文化消费市场整体收紧.上海.广州.吉林.北京等多地爆发的疫情打乱了旅游市场的复苏节奏,国内居民的出游意愿与消费受到影响.国家统计局数据显示,2022上半年,全国居民 ...

  6. Pr:VR 沉浸式视频

    什么是VR视频 Adobe Premiere Pro称全景视频和VR视频为VR沉浸式视频(Immersive Video). 以下说明来自于百度百科(稍有修改) https://baike.baidu ...

  7. 金山云瞄准沉浸式视频云,是远见还是豪赌?

    金山云瞄准沉浸式视频云,是远见还是豪赌? 云计算的未来会走向哪里? 这个问题的答案,可能要从每一个独立个体的发展中去寻找. 从国内云计算市场上这几个主要玩家来看:阿里云正在通过云钉一体.云端一体,为新 ...

  8. 传统豪华品牌引领?智能座舱进入「沉浸式娱乐体验」新周期

    智能座舱正在进入硬件定型.软件(功能)升级以及多应用融合的新周期. 高工智能汽车研究院监测数据显示,2022年中国市场(不含进出口)乘用车搭载智能数字座舱(大屏+语音+车联网+OTA)前装标配交付79 ...

  9. 动态360°沉浸式视频中的人眼注视点预测

    本文出自论文 Gaze Prediction in Dynamic 360° Immersive Videos, 基于时空显著性和历史注视点路径线索,提出了一个深度学习框架来进行未来帧的注视点预测. ...

最新文章

  1. weblogic域,管理服务器,受管服务器,集群和机器的基本知识
  2. 机器学习中的偏差和方差是什么?
  3. saltstack(十二)job管理
  4. 解析:GE工业互联网平台Predix
  5. dNet项目数据访问层代码总结
  6. linux下配置DHCP中继代理
  7. python 判断文件是否被占用_python 在删除文件的时候检测该文件是否被其他线程或者进程占用?...
  8. 小爱音响调用php接口_PHP调用语音合成接口
  9. Mac系统 python3.7安装
  10. python中碰撞的代码_Python…Tkinter碰撞
  11. C++中的cin cout
  12. Unknown failure: Error: java.lang.IllegalStateException: No storage with enough free space; res=-1
  13. bp神经网络数字识别matlab_基于Matlab的BP神经网络识别26个英文字母
  14. java的恐怖推理游戏_胆小勿入!盘点一下2019年所有的恐怖游戏
  15. android 多媒体列表,android – 使用Exoplayer的流媒体视频列表
  16. 【Ruby on Rails全栈课程】3.7 邮件发送(SendCloud、MailGun)
  17. git上传到阿里云code
  18. GitBook运行报错 - Error: ENOENT: no such file or directory, stat
  19. 测试用例设计方法(2)
  20. 《空号》:聊聊我在阿里外包3个月学到了什么。。。

热门文章

  1. 台式电脑:点击开启虚拟机报错:此主机支持intel vy-x, 但intel vy-x处于禁用状态
  2. 深度学习与视频分析简介
  3. 文件服务器锁定账户,文件服务器账户权限设置
  4. MySQL 分库分表实践
  5. Unity批次合并渲染
  6. Mac新手必看教程 Mac系统基本设置 苹果电脑的基本操作
  7. 在微信中点击棋牌游戏类app下载链接显示已停止访问打不开的解决办法
  8. python 函数 求 圆的周长及面积;三角形的面积
  9. 计算机名无法开机,电脑无法开机提示0xc00000bb错误
  10. 一个人简单开发一个网站要多久?需要哪些技术?