这篇文章发布于 2018年05月1日,星期二,19:12,归类于 JS实例。 阅读 63341 次, 今日 8 次 44 条评论
by zhangxinxu from http://www.zhangxinxu.com/wordpress/?p=7526
本文可全文转载,但需要保留原作者和出处,摘要引流则随意。
一、爆款H5中的炫酷场景的技术实现
每年都会迸出一些爆款H5,这些H5通常会有一些酷酷的场景变换。
例如网易Julia H5。创意很棒,传播效果很广,其技术实现就相当简单粗暴,直接一个3分多钟的不带停顿的视频:
类似使用视频的爆款H5还有很多,确实是一个非常不错的解决方案。
但是,视频的实现也有局限:
- iOS下不能自动播放,需要至少touch一次屏幕,这个有时候还挺烦人的,例如我们想做一个H5 app闪屏的时候就蛋疼了。
- 不能在中间穿插棒棒的交互效果,例如,需要视频某一帧暂停,鼠标hover或者touch的时候,当前画面有交互效果,就很不好处理。
- 播放的速率不能随心所欲控制,视频完成也就定死了。
- 如果有些信息是动态的,需要与用户信息关联,则视频方案也会面临很大的调整,因为总不可能每一个用户生成一个不一样的视频,需要辅助额外手段满足需求(例如CSS覆盖定位)。
此时又当如何处理呢?
我们可以使用序列图片,通过JS脚本,来模拟视频播放效果,以上所有局限将通通可以规避。
二、图片列表播放实现方法很多
序列图片视频化技术实现方法很多,例如:
- 合在一张大图上,使用CSS3
animation
控制background-position
实现播放效果。此方法优点是方便快捷,但是,background-position
定位性能不怎么样,只适用于小元素小动画,例如一些loading效果,如果是全屏的大图切换,则在移动设备上可以明显感觉到卡顿; - 合在一张大图上,
transform
定位。性能还是撑不住; - 图片一次性在页面上,依次控制显隐。性能有所提高,但如果图片序列上百帧,图片尺寸较大,性能还是撑不住,客户端说不定会直接闪退。
- 页面上一个
<img>
元素,然后不断改变src
地址,不好意思,也不是很快。
总而言之,上面各种方法都是理论上可行,但实践下来的性能总不尽如人意。
那有没有什么高性能的实现方法呢?
有,一种是使用canvas绘图,但如果想要动态插入其他UI丰富的DOM结构(如登录模块),就比较麻烦;还有一种就是下面这个方法,实践下来性能可以,体验比较好,实现成本也不高。
三、图片播放性能提升的实现方法
实现原理如下:
- 图片DOM对象预加载,放在内存中;
- 播放开始,页面append当前图片DOM,同时移除上一帧DOM图片(如果有),保证页面中仅有一个图片序列元素;
对,很简单,没什么高超的技巧,但就是这种实现策略,对页面的开销是上面几种方法中最小的,最终运行体验是最好的。
眼见为实,您可以狠狠地点击这里:序列图片实现视频播放效果demo
loading完毕,就可以看到一段播放效果——本人飞吻一枚:
效果之流畅,体验之良好,十有八九都会认为是视频,其实不是,就是图片,不断的图片DOM增删实现的类似视频效果。
核心JS代码如下(完整代码见demo),假设container
是容器元素,我们的图片已经预加载到store
对象中,结构如下:
var store = { length: 47, 1: img1, 2: img2, ... 47: img47 };
则有:
var index = 1; container.innerHTML = ''; // 依次append图片对象 var step = function () { if (store[index - 1]) { container.removeChild(store[index - 1]); } container.appendChild(store[index]); // 序列增加 index++; // 如果不超过最大限制,播放下一帧 if (index <= 47) { // 42是按照每秒24帧计算的值 setTimeout(step, 42); } }; step();
上面代码红色高亮是实现的关键,container.removeChild(store[index - 1])
移除之前一帧图片DOM,container.append(store[index])
则是插入当前一帧DOM,人的肉眼习惯连续性感知事物,因此,这种删除和添加,用户是无感知的,于是一个流程的播放效果即达成,根据实践,就算每帧图片在几百K大小主流设备也能hold住。
由于本质上播放的是DOM对象,因此,我们不仅可以播放图片DOM,还可以是有着丰富HTML结构的<div>
元素,于是,什么样的交互实现都不在话下,比方说视频中要出现用户的姓名,怎么办,很简单啊,<div>
元素中定位下就好了。
现在,技术实现已经对设计没有任何限制啦,剩下的就是产品和设计的创意,下一个爆款H5就是你了!
三、番外技能:如何把视频变成序列图片?
如果贵厂有设计师,让设计师处理,基本上,AE之类软件应该都了解。
如果没有设计师,要前端小伙伴自己处理,怎么办?
拿本文的序列图片举例,我是这么处理的:
- 手机视频QQ传到自己电脑;
- 打开Photoshop,然后:文件-导入-视频帧到图层,会出现一个窗口,可以剪切需要导入的视频范围;
如果导入视频很长,建议先剪辑,再导入,除非你的电脑是iMac Pro这种级别的。
- 不做任何处理,直接:“文件-脚本-将图层导出到文件”;
- node.js小工具批量重命名了下(导出图片名称后面序号是准确序号),工具使用的JavaScript代码如下:
var fs = require("fs"); fs.readdir('./', function(err, files) { files.forEach(function(filename) { if (/jpg$/.test(filename) == false) { return; } // 确定新旧文件名称 var oldPath = './' + filename, newPath = './' + filename.split(' ')[1]; // 重命名走起 fs.rename(oldPath, newPath, function() { console.log(filename + '重命名成功!'); }) }); })
四、关于性能其他需要注意的
人眼的跟踪能力要比大猩猩之类要弱的,因此,实际开发,并不一定需要每秒24帧的播放速率,你每秒18帧,对于一个H5运营活动而言,用户是无感知的。每秒18帧的播放可以节约不少请求和加载数据量,性能上也能有所提高,权衡来看,是推荐的,毕竟我们不是去参加动画比赛,是一个在线的web产品。
设计师喜欢使用非常高清的图片,实际上,没有必要,注意度,2倍尺寸,30%~40%的图片质量足够了,效果也非常好,这也是经过实践的,大家如果和设计师意见不一致,就可以让她看我写的这段话。有效降低不必要的图片尺寸,可以大大节约内存的开销,也是可以提高播放的性能和品质的。
于是,三管齐下:高性能技术实现策略,适当降低帧率,优化图片尺寸,必定助你H5炫酷效果流畅至极,好评如潮,boss交口称赞!
以上就是本文内容,感谢阅读,如果文中有表述不准确的地方,欢迎指正!
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=7526
(本篇完)
- 腾讯开源的酷炫动画播放解决方案Vap初体验 (0.614)
- 剪映APP的视频特效如何在Web中JS实现 (0.443)
- 回流与重绘:CSS性能让JavaScript变慢? (0.236)
- 翻译 - CSS Sprites:实用技术还是生厌之物? (0.236)
- 移动页面加速google的AMP和百度的MIP简介 (0.236)
- canvas图形绘制之星空、噪点与烟雾效果 (0.221)
- 基于clip-path的任意元素的碎片拼接动效 (0.221)
- canvas实现iPhoneX炫彩壁纸屏保外加pixi.js流体动效 (0.221)
- CSS CSS3实现3D开门动画效果 (0.221)
- 使用纯CSS实现噪点效果 (0.221)
- HTML audio基础API完全使用指南 (RANDOM - 0.017)
图片序列预加载的逻辑单独开启一个线程(比如:web worker)去加载是不是更快
大佬你好 探讨几个问题
1.性能问题:
CSS3和canvas吊打通过img标签的方式(实测),为啥说这种方式 好?CSS3确实只适合做小范围动画
2.体积问题 视频弄成帧 体积大了很多
滚滚历史红尘往前走,当年写这篇文章时候的手机性能还不是现在这个样子,会有很多老人机。
旭神您好,这个方法有一些问题,IE浏览器及火狐浏览器加载时会闪烁很久,这个问题应该怎样解决
在pc网页中,需要做到摄像头的实时视频播放。我太难了
这个使用canvas读取即可,可以搜索webRTC,有现成demo。
如果是一个10几M的视频,图片需要先预加载吗,预加载多少张比较合适
利用这个方法,15s以上的视频播放,不能正常显示
赞!
大神,加载进度条bgsize的改变看不到效果呀
可以看看我写的这个,完全满足上面需求
backgroundPosition渲染
img标签渲染
backgroundImage渲染
https://github.com/bobby169/cssSprite
你好~我已经在使用你的cssSprite,我有个疑问想咨询一下:请问如果我使用background-position渲染时,该如何适配宽高呢?好像frame数组里只能填写固定的px值,无法随着视窗高度更改呢?
请问声音怎么处理呢,
作为一个小白,想请教一下大神,视频短的可以用gif(2-3s),长的广告图片又有太多(比如15s),这个方法的适用场景有哪些,优势在哪。
示例页面在IE下报错。
SCRIPT438: 对象不支持“append”属性或方法
文件: image-sequence-frame-play.html,行: 221,列: 4
if (store[index – 1]) {
eleContainer.removeChild(store[index – 1]);
}
//HERE!!!
eleContainer.append(store[index]);
// 序列增加
index++;
感谢反馈,已修~
序列图片实现视频播放效果demo
这个点开都是undefined
感谢反馈,已修复。
学习了
张大神可以详细说说为什么增删 DOM 元素比切换 src 更快么?
因为元素已经在内存里面生成好了 而且用过img.onload方法将图片加载好了,如果是改变src的话是在修改的时候才开始下载图片,必然会有闪屏的感觉
挺好玩的呢!!!!!
思路很棒
julia 为什么我先想到了一个女演员
对于有声音的视频来说似乎方案不是那么可行啊
拜读了大神的《CSS世界》,受益匪浅,写得很好,真的,糅合了自己的思考和想法,这是最难能可贵的,读书就像和作者交流,就是要把自己的想法和个性表达出来,写出来,不拘泥于规范和冷冰冰的教程,思想才能碰撞出火花嘛
感谢支持!
我一般是用canvas, 很多逻辑都会写到render里面, 主要是参考的threejs里面的一些做法吧
相见恨晚,感谢提供思路
后面的经验总结很赞!节省调试时间,避免了踩坑!
感谢旭哥提供思路, 我简单封装了个播放器, 献丑了
https://github.com/zhenhappy/images-player
很多时候都会遇到这些问题,学习了
这和上面的第3、4种方法其实差别不大,性能上更好可能只是你的感觉
看云风博客说做梦幻系列时候, 鸣谢名单就是按帧播放图片做的视频效果
思路不错,如下功能如果有就更好了:
1. 边下载边播放
2. 快进快退
3. 声音,关键和快进快退要同步
不过这三个问题,业务开发者可以自己去实现。
1. 边下载边播放也可以做,主要是担心播到一半突然卡住,体验会很不好,倒不如预先都加载完再播
2. 和 3. 都能做
小视频 网速好 完全可以全部加载完再播放,反之 如果没有边下边播,体验会更差。
3 具体怎么做,说下思路。
学习了学习了,前俩天刚好了解到这种原理。今天就刚好看到鑫哥已经写出来了
突如其来的吻让我猝不及防惹
视频看笑了 代码学习了 效果达到了
为啥不考虑直接用 canvas ?
DOM扩展更方便。
canvas和dom按功能区分开呢?
canvas只做视频展示,设置不可点击;其余的还用dom来处理
绝对学习了了,谢谢