作者: 1chigua

  • video标签在不同平台上的事件表现差异分析

    video标签属性和事件介绍

    为了文章的完整性,首先还是列举一下video标签的属性:

    • src :视频的属性
    • poster:视频封面,没有播放时显示的图片
    • preload:预加载
    • autoplay:自动播放
    • loop:循环播放
    • controls:浏览器自带的控制条
    • width:视频宽度
    • height:视频高度

    Video 对象属性:

    • audioTracks: 返回表示可用音频轨道的 AudioTrackList 对象。
    • autoplay: 设置或返回是否在就绪(加载完成)后随即播放视频。
    • buffered: 返回表示视频已缓冲部分的 TimeRanges 对象。
    • controller: 返回表示视频当前媒体控制器的 MediaController 对象。
    • controls: 设置或返回视频是否应该显示控件(比如播放/暂停等)。
    • crossOrigin: 设置或返回视频的 CORS 设置。
    • currentSrc: 返回当前视频的 URL。
    • currentTime: 设置或返回视频中的当前播放位置(以秒计)。
    • defaultMuted: 设置或返回视频默认是否静音。
    • defaultPlaybackRate: 设置或返回视频的默认播放速度。
    • duration: 返回视频的长度(以秒计)。
    • ended: 返回视频的播放是否已结束。
    • error: 返回表示视频错误状态的 MediaError 对象。
    • height: 设置或返回视频的 height 属性的值。
    • loop:设置或返回视频是否应在结束时再次播放。
    • mediaGroup: 设置或返回视频所属媒介组合的名称。
    • muted: 设置或返回是否关闭声音。
    • networkState: 返回视频的当前网络状态。
    • paused: 设置或返回视频是否暂停。
    • playbackRate: 设置或返回视频播放的速度。
    • played: 返回表示视频已播放部分的 TimeRanges 对象。
    • poster: 设置或返回视频的 poster 属性的值。
    • preload: 设置或返回视频的 preload 属性的值。
    • readyState: 返回视频当前的就绪状态。
    • seekable: 返回表示视频可寻址部分的 TimeRanges 对象。
    • seeking: 返回用户当前是否正在视频中进行查找。
    • src: 设置或返回视频的 src 属性的值。
    • startDate: 返回表示当前时间偏移的 Date 对象。
    • textTracks: 返回表示可用文本轨道的 TextTrackList 对象。
    • videoTracks: 返回表示可用视频轨道的 VideoTrackList 对象。
    • volume: 设置或返回视频的音量。
    • width :设置或返回视频的 width 属性的值。

    Video 对象方法:

    • addTextTrack(): 向视频添加新的文本轨道。
    • canPlayType(): 检查浏览器是否能够播放指定的视频类型。
    • load(): 重新加载视频元素。
    • play(): 开始播放视频。
    • pause(): 暂停当前播放的视频。

    然后列出可以用于视频状态监控的Media 事件(由媒介(比如视频、图像和音频)触发的事件,适用于所有html元素,但常用于 audio、embed、img、object 以及 video中):

    属性描述
    onabortscript在退出时运行的脚本
    oncanplayscript当文件就绪可以开始播放时运行的脚本(缓冲已足够开始时)
    oncanplaythroughscript当媒介能够无需因缓冲而停止即可播放至结尾时运行的脚本
    ondurationchangescript当媒介长度改变时运行的脚本
    onemptiedscript当发生故障并且文件突然不可用时运行的脚本(比如连接意外断开时)
    onendedscript当媒介已到达结尾时运行的脚本(可发送类似“感谢观看”之类的消息)
    onerrorscript当在文件加载期间发生错误时运行的脚本
    onloadeddatascript当媒介数据已加载时运行的脚本
    onloadedmetadatascript当元数据(比如分辨率和时长)被加载时运行的脚本
    onloadstartscript在文件开始加载且未实际加载任何数据前运行的脚本
    onpausescript当媒介被用户或程序暂停时运行的脚本
    onplayscript当媒介已就绪可以开始播放时运行的脚本
    onplayingscript当媒介已开始播放时运行的脚本
    onprogressscript当浏览器正在获取媒介数据时运行的脚本
    onratechangescript每当回放速率改变时运行的脚本(比如当用户切换到慢动作或快进模式)
    onreadystatechangescript每当就绪状态改变时运行的脚本(就绪状态监测媒介数据的状态)
    onseekedscript当 seeking 属性设置为 false(指示定位已结束)时运行的脚本
    onseekingscript当 seeking 属性设置为 true(指示定位是活动的)时运行的脚本
    onstalledscript在浏览器不论何种原因未能取回媒介数据时运行的脚本
    onsuspendscript在媒介数据完全加载之前不论何种原因终止取回媒介数据时运行的脚本
    ontimeupdatescript当播放位置改变时(比如当用户快进到媒介中一个不同的位置时)运行的脚本
    onvolumechangescript每当音量改变时(包括将音量设置为静音)时运行的脚本
    onwaitingscript当媒介已停止播放但打算继续播放时(比如当媒介暂停已缓冲更多数据)运行脚本

    这些Media 事件在不同平台下表现各异,事件触发的场景有差异,事件触发后Video对象属性的返回值也不尽相同,下面重点归纳其差异点,首先我们会给出结论,然后附上测试数据。 测试直接使用最简单的方式,在页面上添加video标签播放视频,视频设置循环播放属性loop。

    差异分析结论

    事件属性表现差异

    eventpc侧iOSandroid
    loadstart文件加载,video初始化,未加载任何数据与PC侧一致一致
    stalled视频没有播放,没有取回任何媒介数据:一般是由于网络状况不佳,导致视频下载中断一致可能在play()事件触发前
    playplay()事件触发,状态是开始播放,但视频并未真正开始播放一致一致
    waitingplay()事件触发后,等待数据一致一致
    durationchange获取到视频长度,duration属性能获得真实视频长度一致可能在play()事件触发前,可能没有获取到真实的视频长度:可能触发多次, 只有最后一次才能获取到真实的duration,之前的值有可能为0或者1
    loadedmetadataplay()事件触发后,获取到元数据一致play()事件触发前,没有获取到真实的元数据
    loadeddataplay()事件触发后,获取到媒介数据一致play()事件触发前,没有获取到真实的媒介数据
    canplay可以播放,但视频可能还未真正开始播放,并且中途可能因为加载而暂停一致一致
    playing视频开始播放一致可能还未真正开始播放,并且可能还未获取到视频长度
    canplaythrough视频开始播放后,可以流畅播放一致数据可能还没有开始加载,视频可能还未开始播放, 视频仍然会卡住
    timeupdate视频播放后,更新播放进度, 会有明确的进度变化,可以获取到currentTime一致第一次可能会有误差,如果 timeupdate事件的currentTime发生变化,代表视频一定开始播放
    progress视频播放后,持续下载, 可以获取到当前的缓存buffer,并且全部下载完毕后不再触发一致第一次可能会有误差, 全部下载完毕后依然继续触发
    suspend缓冲中,视频可能卡顿也可能在流畅播放中,全部缓存完毕后不再触发。视频还未真实播放前,pause()事件会触发suspend一致一致
    pause可能是响应pause()事件暂停,或者是切出页面自动暂停一致一致
    seeking拖动进度条时,寻找播放位置。或者播放完毕,寻找下一个视频一致一致
    seeked拖动进度条时,定位到播放位置。或者开始播放下一个视频,或者是从头开始循环播放一致一致
    error错误,无法定位错误原因,无法通过paly()事件继续播放一致一致

    视频监控结论

    首先重点介绍video对象的buffered属性:

    buffered返回 TimeRanges 对象,TimeRanges 对象表示用户已缓冲音视频的时间范围,如果用户在音视频中跳跃播放,会得到多个缓冲范围。这里要强调的是如果跳跃播放,得到的多个缓冲范围是按照大小顺序排列,无重复覆盖的

    |

    目前可以监控的事件有以下几点:

    1、 视频加载时间

    play事件触发时间 至 timeupdate事件第一次currentTime 属性值发生变化时,在加载过程中可用suspend判断是否有手动暂停。

    2、 视频缓冲次数

    video对象的buffered属性返回表示视频已缓冲部分的 TimeRanges 对象,currentTime属性设置或返回视频中的当前播放位置(以秒计),利用缓冲区的变化可以记录视频缓冲次数。 目前尝试的缓冲判断为: timeupdate事件中,currentTime 超出 buffered的记录范围。

    3、 视频流中断

    引起视频停止播放的原因有:手动暂停、视频流中断、视频播放完毕,切换程序,所以用视频停止播放来判断断流不准确。 要尽可能的实时监控视频流是否中断,目前还是尝试使用video对象的buffered属性, 因为视频断流意味着buffered缓冲区不会再发生变化。 视频流中断判断可表述为: timeupdate事件中,currentTime所在的缓冲buffered段的尾部时间,不等于视频的总长度duration, 且连续多次没有变化。具体使用连续多少次作为阈值,需要反复测试,目前所得结论是20次。

    测试数据

    pc侧chrome

    #eventreadyStatecurrentTime (s)buffered (s)duration (s)视频状态
    1loadstartNOTHING0nullNaN准备请求数据(初始化完毕)
    2stalledNOTHING0nullNaN
    3playNOTHING0nullNaNplay()事件触发,状态是开始播放,但视频并未真正开始播放
    4waitingNOTHING0nullNaN等待数据
    5durationchangeMETADATA00.644.2获取到视频长度
    6loadedmetadataMETADATA00.644.2获取到元数据
    7loadeddataENOUGH_DATA01.0644.2
    8canplayENOUGH_DATA01.0644.2可以播放,但中途可能因为加载而暂停
    9playingENOUGH_DATA01.0644.2开始播放
    10canplaythroughENOUGH_DATA01.0644.2可以流畅播放
    11timeupdateENOUGH_DATA01.0644.2播放进度变化
    12progressENOUGH_DATA0.12.9244.2持续下载
    13timeupdateENOUGH_DATA0.214.6744.2播放进度变化
    38suspendENOUGH_DATA3.2914.0844.2缓冲中,视频可能卡顿也可能在流畅播放中
    39timeupdateENOUGH_DATA3.4814.0844.2
    490timeupdateENOUGH_DATA39.744.244.2
    491pauseENOUGH_DATA39.8744.244.2手动暂停
    492playENOUGH_DATA39.8744.244.2play()事件触发
    493playingENOUGH_DATA40.0644.244.2
    494timeupdateENOUGH_DATA40.2444.244.2
    509timeupdateENOUGH_DATA43.9944.244.2
    510timeupdateMETADATA044.244.2播放完毕
    511seekingMETADATA044.244.2寻找中
    512waitingMETADATA044.244.2
    513progressMETADATA044.244.2
    514timeupdateENOUGH_DATA044.244.2
    515seekedENOUGH_DATA0.0544.244.2播放完毕进度回到起点循环播放
    516canplayENOUGH_DATA0.2544.244.2
    802timeupdateENOUGH_DATA23.4644.244.2
    803errorENOUGH_DATA044.244.2网络断开错误
    804timeupdateENOUGH_DATA044.244.2无法继续播放

    iOS

    iOS weixin

    #eventreadyStatecurrentTime (s)buffered (s)duration (s)视频状态
    1loadstartNOTHING0nullNaN准备请求数据(初始化完毕)
    2playNOTHING0nullNaN状态是开始播放,但视频并未真正开始播放
    3waitingNOTHING0nullNaN等待数据
    4durationchangeMETADATA07.6344.2获取到视频长度
    5loadedmetadataMETADATA07.6344.2获取到元数据
    6loadeddataENOUGH_DATA07.6344.2
    7canplayENOUGH_DATA07.6344.2可以播放,但中途可能因为加载而暂停
    8canplaythroughENOUGH_DATA07.6344.2可以流畅播放
    9playingENOUGH_DATA07.6344.2开始播放
    10timeupdateENOUGH_DATA07.6344.2播放进度变化
    11timeupdateENOUGH_DATA0.257.6344.2
    22timeupdateENOUGH_DATA3.0136.2444.2
    23progressENOUGH_DATA3.1544.244.2持续下载
    24suspendENOUGH_DATA3.1644.244.2
    25timeupdateENOUGH_DATA3.2644.244.2
    39pauseENOUGH_DATA6.4744.244.2手动暂停
    40playENOUGH_DATA6.5144.244.2
    41playingENOUGH_DATA6.544.244.2
    42timeupdateENOUGH_DATA6.7244.244.2
    61timeupdateENOUGH_DATA11.444.244.2
    62pauseENOUGH_DATA11.444.244.2网络环境切换,自动触发
    63playENOUGH_DATA11.3844.244.2
    64playingENOUGH_DATA11.4144.244.2
    65timeupdateENOUGH_DATA11.644.244.2
    198timeupdateENOUGH_DATA44.1544.244.2
    199timeupdateENOUGH_DATA044.244.2播放完毕
    200seekingENOUGH_DATA044.244.2寻找中
    201timeupdateENOUGH_DATA0.144.244.2
    202seekedENOUGH_DATA0.244.244.2播放完毕进度回到起点循环播放
    203timeupdateENOUGH_DATA0.3744.244.2

    iOS QQ

    与微信无明显差异

    iOS safari

    与微信无明显差异

    iOS QQ浏览器 x5内核

    #eventreadyStatecurrentTime (s)buffered (s)duration (s)视频状态
    1loadstartNOTHING0nullNaN准备请求数据(初始化完毕)
    2progressMETADATA0null44.2
    3suspendMETADATA0null44.2
    4durationchangeMETADATA0null44.2
    5loadedmetadataMETADATA0null44.2未触发play()事件之前,自动触发以上事件
    6timeupdateMETADATA0null44.2触发play()事件,开始播放
    7timeupdateMETADATA0null44.2
    8timeupdateMETADATA0null44.2

    在QQ浏览器中除了可以获取视频长度,其他属性均无法获取。鉴于其表现比较诡异,我们的对比中除开此特例。

    android–三星GT-N7105 4.4.2

    android weixin

    <

    #eventreadyStatecurrentTime (s)buffered (s)duration (s)视频状态
    1loadstartCURRENT_DATA0null1准备请求数据(初始化完毕)
    2durationchangeCURRENT_DATA0null1
    3loadedmetadataCURRENT_DATA0null1
    4loadeddataCURRENT_DATA0null1
    5stalledCURRENT_DATA0null1

  • HTML audio基础API完全使用指南

    本文介绍HTML5 <audio>音频元素的属性,方法,以及事件相关的API的基本使用。

    本文内容对于HTML5 <video>视频元素同样受用。

    内容有些多,完整阅读需要点时间,但很实用,可以先马后看。

    一、audio使用基本案例

    <audio controls> <source src=”audiofile.mp3″ type=”audio/mpeg”> <source src=”audiofile.ogg” type=”audio/ogg”> <!– 如果浏览器不支持,则会呈现下面内容 –> <p>你的浏览器不支持HTML5音频,你可以<a href=”audiofile.mp3″>下载</a>这个音频文件。</p> </audio>

    上面做法是早些年HTML5 <audio>常用代码,因为那时候IE8还是大头,各大浏览器对各类音频格式支持情况参差不齐,因此,才借助<source>元素同时引用多个不同格式的音频文件,通过type属性指定mime type避免重复加载情况出现。

    但是,如今已经不需要这么麻烦了。我们直接下面这样就可以了:<audio src=”audiofile.mp3″ controls></audio>

    音频文件常见下面3种格式,.ogg, .wav和.mp3,其中,.ogg Safari浏览器不支持(目前版本13),IE到Edge16都不支持;.wav则是IE-IE11不支持;但是.mp3 IE9+都支持。因此,我们如果不想麻烦,直接一个MP3格式就好了,由于就一种文件格式,因此type属性也可以不用设置。

    //zxx: 也可以使用MP4视频文件,因为MP4视频也包含ACC编码音频,不过就是体积大了很多,不建议这么使用。

    <audio>元素IE9浏览器就开始支持,现在00后都快20岁了,也不需要为低版本浏览器做降级适配了。因此,简简单单一个<audio>元素就可以了。

    二、Audio HTML属性

    下面看下<audio>元素属性相关的一些细节。

    autoplay

    <audio src=”audiofile.mp3″ autoplay></audio>

    autoplay是个布尔属性值,表示声音是否自动播放,默认不自动播放。然而,随着浏览器的发展,这个属性变得限制越来越多。首先在移动端,autoplay自动播放已经被禁止了,PC端也已经禁止,18年的时候,Chrome这么做了,然后被很多开发者抗议,后来又恢复autoplay(给大家缓冲时间),现在已经Chrome又不支持自动播放了。

    原因是网页在没有警告的情况下自发地发出声音,可能会让用户不愉快,体验不太好。因此,浏览器通常只允许在特定情况下成功地进行自动播放。

    关于更深入的autoplay策略可以参见MDN上的这篇文档

    不过根据我自己的一些实践,资源静音或者视频没有声音情况下,autoplay偶尔也是会执行的,不过都是偶现,触发自动播放原因不详。

    loop

    <audio src=”audiofile.mp3″ loop></audio>

    loop是个布尔属性值,表示声音是否循环播放,默认不循环播放。loop属性适合用在可以不断循环的bgm背景音乐上。loop属性在各个平台,各个浏览器下的表现良好,大家可以放心使用。

    JS设置音频循环播放可以:document.querySelector(‘audio’).loop = true;

    muted

    示意:<audio src=”audiofile.mp3″ muted></audio>

    muted也是个布尔属性值,表示音频是否静音,默认不静音播放。muted属性在各个平台,各个浏览器下的表现良好,大家可以放心使用。

    JS设置音频静音可以:document.querySelector(‘audio’).muted = true;

    preload

    示意:<audio src=”audiofile.mp3″ preload=”auto”></audio>

    preload可以指定音频的预加载策略,也就是在播放之前需要提前加载好音频的哪些资源。支持下面3个属性值:

    1. none:表示在点击播放按钮之前不加载任何信息。
    2. metadata: 下载音频的meta信息,就是视频长度,类型,还有作者(如果有)等信息。/li>
    3. auto: 会尝试下载整个音频,如今5G都快来了,流量已经不值钱了,因此,我个人是更推荐使用auto的,体验更好一点。然后,通常浏览器自己也会优化加载策略,不会所有音频文件都加载下来,只是会加载一部分,保证点击播放按钮的时候,可以立即播放。

    preload属性在iOS Safari浏览器下是被禁止的(桌面端无此问题),对于一些对音频播放时间实际要求比较高的场合,会给我们开发带来困难。通常解决方法是,第一次触摸的时候,音频静音,同时触发音频play()然后很快再pause(),此时,可以有类似preload的预加载行为。

    不过,Safari以后可能会改变preload在移动端的加载策略,因为越往后流量越不值钱,这种自以为是的优化反而会成为一种桎梏。

    controls

    示意:<audio src=”audiofile.mp3″ controls></audio>

    controls是个布尔属性值,表示声音是否显示音频播放暂停等控制器,默认是不显示的。

    如果没有设置controls属性,整个音频文件播放面板都是完全隐藏的;如果有设置,则UI可能类似下面这张图(Chrome PC,设置了静音)。

    不同浏览器,以及不同版本浏览器,其UI都不一样。如果是开发to用户侧产品,需要自定义音频播放器的UI,让各个浏览器下长相一致,大家可以去github上找找开源的项目。

    src

    示意:<audio src=”audiofile.mp3″></audio>

    src属性表示音频的文件地址。可以用在<audio>元素上,也可以用在<source>元素上。<audio>元素上只能一个音频地址,使用<source>可以并列多个不同格式的音频文件。

    type

    <audio src=”audiofile.mp3″ type=”audio/mpeg”></audio>

    type属性用来指定音频文件的mime type类型。虽然不加type类型,浏览器也能正确播放音频文件,但通常建议加上type属性。当然,如果src音频格式不固定,则type属性反而推荐不加,错误的type不如没有type

    三、在JS中调用的audio属性

    <audio>元素还有一些属性只能通过JavaScript设置,假设有HTML如下:<audio id=”myAudio” src=”audiofile.mp3″></audio>

    则:

    currentTime

    currentTime是一个可读兼可写的属性,用来设置或获取当前已经播放的时长,单位是秒。

    例如:// 获取音频已经播放时长 var playedTime = myAudio.currentTime;

    如果音频尚未开始播放,则playedTime的返回值是0

    我们也可以通过设置currentTime属性值,让我们的音频定位到我们希望的时间点进行播放,例如,从5秒那里开始播放,则:// 跳到5秒那里 myAudio.currentTime = 5;

    volume

    volume也是一个可读兼可写的属性,用来设置或获取音频的音量大小,范围是0-1。

    例如,设置音量50%,则:// 设置音量50% myAudio.volume = 0.5;

    如果音频文件设置了mutedtrue,则myAudio.volume的返回值是0

    playbackRate

    playbackRate是一个可读兼可写的属性,用来设置或获取当前媒体文件的播放速率,值为数值,例如:// 获取音频播放速率 var audioSpeed = audio.playbackRate; // 设置音频设置播放速率为正常速度的1.5倍 audio.playbackRate = 1.5;

    速率范围

    根据文档显示,Gecko内核浏览器速率范围是0.25到5.0,超出这个范围就静音。

    对于Chrome浏览器,我自己实地测试了下,速率上限居然可以到16,如下图:

    然后,此属性兼容性不错,IE9+都支持。

    paused

    paused是一个只读属性,表示当前音频是否处于暂停状态。// true或false console.log(myAudio.paused);

    未播放或者播放暂停都会返回true

    四、播放与暂停等JS方法

    play()

    音频播放示意,没有额外参数:myAudio.play();

    需要注意的是,目前在现代浏览器下,无论是桌面端还是移动端,执行myAudio.play()不总是有效果的。

    目前策略是,web网页需要至少又一次可信任的用户行为后,才能myAudio.play()播放才可以执行,否则会报错。

    报错场景

    可信任的用户行为包括touchstart触摸或者click点击。

    更新于2020-11-20

    Chrome浏览器50之后的版本, <video>或者<audio>执行play()方法后返回的是一个Promise。

    play()方法是一个异步过程,如果先play()方法然后立即执行pause()方法会报错:

    Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().

    即使加一个定时器(时间如果不是很足够),也会报这个错误,此时可以使用下面的语法:<script> // 播放开始,可能会显示loading var playPromise = audio.play(); if (playPromise !== undefined) { playPromise.then(_ => { // 这里就已经开始播放了 // 播放UI会出现(如果控件显示的话) // 此时可以安全的暂停音视频了 audio.pause(); }).catch(error => { // 无法自动播放 // 显示暂停的UI }); } </script>

    pause()

    音频暂停示意,没有额外参数:myAudio.pause();

    音频元素是没有stop()方法的,如果你想要实现音频的stop()效果,可以先设置currentTime属性值为0,然后在执行pause()方法。

    canPlayType()

    canPlayType()可以用来检测浏览器是否支持某种类型的音频文件,支持一个mime type值作为参数。使用示意:if (myAudio.canPlayType(‘audio/mpeg’)) { // 如果支持mp3 // 这里搞事情 }

    canPlayType()方法可以返回下面三个值中的某一个:

    1. probably
    2. maybe
    3. ""(空字符串)

    实际开发的时候,只要不是空字符串,我们都可以认为是支持的,因此,直接使用if弱匹配返回值即可,例如:var myAudio = document.createElement(‘audio’); if (myAudio.canPlayType(‘audio/mpeg’)) { myAudio.setAttribute(‘src’,’audiofile.mp3′); } if (myAudio.canPlayType(‘audio/ogg’)) { myAudio.setAttribute(‘src’,’audiofile.ogg’); }

    load()

    触发音频文件的加载。如果浏览器不支持preload属性,则此方法也不会有效果。

    此方法没有额外参数:myAudio.load();

    五、音频媒体加载事件

    下面讲讲关于音频加载及相关处理,根据我实际项目中的实践,这类加载事件在移动端,尤其iOS Safari并不总能触发,因为preload以及autoplay等属性的限制。

    loadstart

    loadstart事件简单地告诉我们加载过程已经开始,浏览器正在连接到媒体。myAudio.addEventListener(“loadstart”, function() { // 抓取文件 });

    durationchange

    如果你想尽快知道音频文件的播放时长,则durationchange事件非常管用,因为音频文件默认duration初始值是NaN,当准确时长返回时候,会触发durationchange,此时我们就可以快速显示音频播放时间了。

    通常实际开发,我们会使用00:00占位,durationchange事件触发后在替换为准确的总播放时间。myAudio.addEventListener(“durationchange”, function() { // 可以显示播放时长了哟 });

    loadedmetadata

    当第一个音频文件字节数据到达时,会触发loadeddata事件。虽然播放头已经就位,但还没有准备好播放。myAudio.addEventListener(“loadeddata”, function() { // 可以显示播放头 });

    progress

    progress事件在媒体文件仍然在下载中的时候触发,通常各种loading效果的显示就是在这个事件中。myAudio.addEventListener(“progress”, function() { // 你可以让用户知道媒体文件正在下载 });

    canplay

    当媒体文件可以播放的时候会触发canplay事件。

    我们在自定义音频播放器的时候,可以默认把一些按钮disabled禁用,等可以播放的时候再恢复为enabled,此时就可以使用canplay事件。myAudio.addEventListener(“canplay”, function() { // 音频可以播放了 });

    canplaythrough

    canplaythrough事件在音频文件可以从头播放到尾时候触发。这种情况包括音频文件已经从头到尾加载完毕了,或者浏览器认为一定可以按时下载,不会发生缓冲停止。myAudio.addEventListener(“canplaythrough”, function() { // 音频可以不发生缓冲从头播放到结束 });

    音频事件触发的顺序

    媒体事件加载顺序如下:

    loadstart → durationchange → loadedmetadata → loadeddata → progress → canplay → canplaythrough

    加载中断事件

    还有一些事件实在媒体加载过程出现某种中断时将触发。suspend即使文件尚未完全下载,也不再拉取媒体数据。abort不是因为出错而导致的媒体数据下载中止。error媒体下载过程中错误。例如突然无网络了。或者文件地址不对。emptied媒体缓冲区已被清空,可能是由于错误或调用了load()方法重新加载。stalled媒体数据意外地不再可用。

    六、音频媒体播放事件

    下面介绍一些与媒体文件播放状态相关的一些事件。

    timeupdate

    每次currentTime属性值发生变化的时候会触发timeupdate事件。

    实际开发的时候,这个事件每250毫秒出发一次。这个事件可用来实时显示播放进度。myAudio.addEventListener(“timeupdate”, function() { // 更新与播放进度相关的内容 });

    playing

    音频文件在缺少媒体信息(如时长等)的时候,播放会被迫停止,如果之后在启动播放,会触发playing事件。

    waiting

    音频文件因为缺少媒体信息(如时长等)导致播放停止时会触发waiting事件。

    play

    play事件在play()方法生效,或者autoplay导致播放开始时候触发,此事件触发的播放状态一定是一个从暂停到播放。

    pause

    pause事件在pause()方法执行并生效后触发,此事件触发需要一个从播放到暂停的状态变化。

    ended

    当整个音频文件播放完毕的时候触发ended事件。myAudio.addEventListener(“ended”, function() { // 当音轨播放完毕时候做你想做的事情 });

    volumechange

    音量发生变化的时候会触发volumechange事件,包括静音行为。

    ratechange

    播放速率发生变化的时候会触发ratechange事件。

    七、缓冲相关的属性和方法

    媒体文件的播放进度我们可以使用currentTimeduration属性获取,但是有时候,我们希望知道缓冲加载的进度,此时可以使用下面几个和缓冲相关属性和方法。

    buffered

    此属性让我们知道音频的哪些部分已被缓冲(提前下载)。它返回一个称为TimeRanges的对象。myBufferedTimeRanges = myAudio.buffered;

    seekable

    seekable属性通知您是否可以直接跳到媒体的该部分,而不需要进一步缓冲。mySeekableTimeRanges = myAudio.seekable;

    Buffering相关事件seeking当媒体资源正在请求是会触发seeking事件。seekedseeking属性变成false时候会触发seeked事件。

    有关缓冲以及TimeRanges更深入具体的知识,可以参见这篇MDN文档

    亚马逊云科技@艾特你 立即免费使用 12 个月 EC2, RDS 等企业级云服务广告

    八、结语与参考文档

    本文展示的这些<audio>音频元素相关的属性和方法以及各种回调事件,对于<video>视频元素同样受用,基本上都是一模一样的,很多自动播放以及媒体自动加载策略也是一致的。

    本文展示的这些API并不是全部,如果发现有遗漏,欢迎大家补充。

    参考文档

    感谢阅读,欢迎交流!

  • Go语言:让我印象深刻的13个特性

    1、兼顾开发效率和性能

    Go语言兼顾开发效率和性能。可以像Python那样有很快的开发速度,也可以像C++那样有很快的执行速度。

    2、编译速度很快

    编译速度很快,减少编译等待时间。其实编译时间长,对开发人员未必是坏事,可以有个正当理由摸鱼了,哈哈!

    3、没有面向对象的束缚

    Go语言有些面向对象的特性,没有太多面向对象的束缚,但是一样可以做到代码复用。

    Go语言虽然不是面向对象的语言,但是依然支持面向对象的开发模式,只是没有继承这种特性。

    Go语言推荐使用组合而非继承的设计模式,只需要将一种类型嵌入到另一种类型,就能复用所有的功能。

    4、自带垃圾回收器

    自带垃圾回收器,不需要用户自己管理内存。

    5、最吸引我的特性  —  并发

    Go语言最吸引我的特性的是它天生对并发的支持。采用了类似虚拟线程的概念,使用很少的代码,占用更少的内存,就可以写出复杂的并发程序。

    Go语言的并发同步模型,是以消息传递为模型。通过通道(channel)在各个goroutine之间传递消息,来实现同步访问,而非通过对数据加锁来实现同步,这一点与其他语言不同。

    Go语言内部实现了一个逻辑处理器,每个逻辑处理器对应一个线程,每个逻辑处理器可以处理多个并发程序。正是因为这种并发程序不会独占线程的方式,所以Go语言的并发会占用更少的线程和内存。

    6、独特的接口实现机制

    Go语言具有独特的接口实现机制,允许用户对行为进行建模,而不是对类型进行建模。

    在Go语言中,不需要声明某个类型实现了某个接口,编译器会自动判断一个类型的实现是否符合正在使用的接口。

    说白了就是不需要强制指定某个类实现了某个接口。

    7、独特的_符号

    Go语言的_特性是为了让程序的可读性更强,Go编译器不允许声明导入某个包却不使用,也不允许在函数中声明了某个变量却不使用。

    8、init函数

    Go语言中可以定义init函数,程序中每个代码文件里的init函数都会在main函数执行前调用。

    9、允许一个函数返回多个值

    Go语言中允许一个函数返回多个值,单就这一点就可以让程序员写代码更舒心了,有时候代码写的很舒畅的时候,突然为了几个简单的返回值再去定义一个对象,实在有点糟心。

    10、所有的变量都以值的方式传递。

    Go语言中,所有的变量都以值的方式传递。指针变量有点特殊。因为指针变量的值是所指向的内存地址,在函数间传递指针变量,是在传递这个地址值,所有依旧被看做以值的方式在传递。

    11、支持闭包

    Go语言支持闭包,在闭包里并不是拿到外部变量的副本,而是直接访问外层函数作用域中声明的这些变量本身。

    12、关键字Defer

    Defer后的代码会在函数返回时才会执行。哪怕函数意外奔溃终止,也能保证Defer安排的函数会被执行。

    引入这个关键字的初衷是为了提高代码可读性。可以将打开、关闭资源的代码成对靠近的写在一起,避免了try…catch…finally这样散落的代码组织形式。

    13、函数和方法

    Go语言有些函数式编程的特性。Go语言中有函数和方法,他俩的区别是:如果声明的函数带有接受者,则是方法。

    方法的接受者分为:指针接受者、值接受者。使用指针接受者的方法,只能使用指针类型调用。使用值接受者的方法,使用指针类型和值类型都可以调用。

  • text-overflow

    https://developer.mozilla.org/zh-CN/docs/Web/CSS/text-overflow

    text-overflow CSS 属性用于确定如何提示用户存在隐藏的溢出内容。其形式可以是裁剪、显示一个省略号(“”)或显示一个自定义字符串。

  • 获取input上传文件文件名及扩展名

    //获取一个上传文件的扩展名
    		var myfile = document.getElementById('myfile');
    		var mybtn = document.getElementById('mybtn');
    		mybtn.onclick = function(){
    			//获取文件上传文件的文件名和扩展名
    			if(myfile.files[0] == undefined){
    				alert('未上传文件!');
    			}else{
    				//获取上传文件的文件名
    				alert(<span style="color:#FF0000;">myfile.files[0].name</span>);
    			}
    			//获取上传文件的扩展名
    			var filevalue = myfile.value;
    			var index = filevalue.lastIndexOf('.');
    			alert(<span style="color:#FF0000;">filevalue.substring(index)</span>);
    		}
    
    ————————————————
    版权声明:本文为CSDN博主「可乐6666」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/xuexizhe88/article/details/52165704
  • JavaScript 将字符串中间替换为省略号


    例如我有一个很长的字符串 "1b3ea107c06ced8604ec95ddb9b37d3b",只想显示前8位与后7位,中间显示三个点

    实现

    function shortStr(text){
        return text.slice(0,8) + "..." + text.slice(-7);
    }
    
    shortStr("1b3ea107c06ced8604ec95ddb9b37d3b")

    Copy

    最终得到字符串 "1b3ea107...9b37d3b"

    说明

    其中 slice(0,8) 表示截取前8位字符串,slice(-7) 表示截取后7位字符串