audio 在瀏覽器中自動播放
autoplay 屬性
autoplay 屬性規定一旦音頻就緒馬上開始播放。
如果設置了該屬性,音頻將自動播放。
使用 autoplay 屬性進行播放
//使用autoplay屬性
var src = "./award.wav";
var body = document.getElementsByTagName("body")[0];
if (body.getElementsByTagName("audio").length <= 0) {
var audio = document.createElement("audio");
audio.setAttribute("id", "awardAudio");
audio.setAttribute("autoplay", "autoplay");
audio.setAttribute("src", src);
body.appendChild(audio);
setTimeout(function() {
body.removeChild(audio);
}, 2300);
}
oncanplaythrough 事件
oncanplaythrough 事件在視頻/音頻(audio/video)可以正常播放且無需停頓和緩沖時觸發。
在視頻/音頻(audio/video)加載過程中,事件的觸發順序如下:
- onloadstart
- ondurationchange
- onloadedmetadata
- onloadeddata
- onprogress
- oncanplay
- oncanplaythrough
//1
<audio oncanplaythrough="event">
//2
audio.oncanplaythrough=function(){event()};
//3
audio.addEventListener("canplaythrough", event;
監聽 canplaythrough 事件進行播放
// 監聽加載事件執行play方法
var src = "./award.wav";
var body = document.getElementsByTagName("body")[0];
if (body.getElementsByTagName("audio").length <= 0) {
var audio = document.createElement("audio");
audio.setAttribute("id", "awardAudio");
audio.setAttribute("src", src);
body.appendChild(audio);
//判斷音頻是否加載完成?
audio.addEventListener(
"canplaythrough",
function() {
audio.play();
setTimeout(function() {
body.removeChild(audio);
}, audio.duration * 1000 + 100);
},
false
);
}
duration 在 autoplay 下回失效,返回 NaN
JS 報錯:Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.
https://goo.gl/xX8pDD這里是官方給出的解釋,chrome66 之后反正是不能用了
解決方法
- 在 chrome 瀏覽器中輸入 chrome://flags/#autoplay-policy
- 在 Autoplay policy 下拉中設置無需用戶手勢
- 重啟 chrome
或
- chrome.exe --disable-features=AutoplayIgnoreWebAudio
- MDN->audio 屬性
- src 歌曲的路徑
- preload 是否在頁面加載后立即加載(設置 autoplay 后無效)
- controls 顯示 audio 自帶的播放控件
- loop 音頻循環
- autoplay 音頻加載后自動播放
- currentTime 音頻當前播放時間
- duration 音頻總長度
- ended 音頻是否結束
- muted 音頻靜音為 true
- volume 當前音頻音量
- readyState 音頻當前的就緒狀態
- MDN->audio 事件
- abort 當音頻/視頻的加載已放棄時
- canplay 當瀏覽器可以播放音頻/視頻時
- canplaythrough 當瀏覽器可在不因緩沖而停頓的情況下進行播放時
- durationchange 當音頻/視頻的時長已更改時
- emptied 當目前的播放列表為空時
- ended 當目前的播放列表已結束時
- error 當在音頻/視頻加載期間發生錯誤時
- loadeddata 當瀏覽器已加載音頻/視頻的當前幀時
- loadedmetadata 當瀏覽器已加載音頻/視頻的元數據時
- loadstart 當瀏覽器開始查找音頻/視頻時
- pause 當音頻/視頻已暫停時
- play 當音頻/視頻已開始或不再暫停時
- playing 當音頻/視頻在已因緩沖而暫停或停止后已就緒時
- progress 當瀏覽器正在下載音頻/視頻時
- ratechange 當音頻/視頻的播放速度已更改時
- seeked 當用戶已移動/跳躍到音頻/視頻中的新位置時
- seeking 當用戶開始移動/跳躍到音頻/視頻中的新位置時
- stalled 當瀏覽器嘗試獲取媒體數據,但數據不可用時
- suspend 當瀏覽器刻意不獲取媒體數據時
- timeupdate 當目前的播放位置已更改時
- volumechange 當音量已更改時
- waiting 當視頻由於需要緩沖下一幀而停止
在react中做成組件
/**
* Created by easterCat on 2017/10/13.
*/
import React from 'react';
import ReactDOM from 'react-dom';
import {connect} from 'react-redux';
import {Icon} from 'antd';
class RecordAudio extends React.Component {
constructor(props) {
super(props);
this.state = {
isPlay: false,
openMuted: false,
volume: 100,
allTime: 0,
currentTime: 0
};
this.millisecondToDate = (time) => {
const second = Math.floor(time % 60);
let minite = Math.floor(time / 60);
return `${minite}:${second >= 10 ? second : `0${second}`}`
};
this.controlAudio = (type, e) => {
const audio = ReactDOM.findDOMNode(this.refs['audio']);
switch (type) {
case 'allTime':
this.setState({
allTime: audio.duration
});
break;
case 'play':
audio.play();
this.setState({
isPlay: true
});
break;
case 'pause':
audio.pause();
this.setState({
isPlay: false
});
break;
case 'changeCurrentTime':
this.setState({
currentTime: e.target.value
});
audio.currentTime = e.target.value;
if (e.target.value === audio.duration) {
this.setState({
isPlay: false
})
}
break;
case 'getCurrentTime':
this.setState({
currentTime: audio.currentTime
});
if (audio.currentTime === audio.duration) {
this.setState({
isPlay: false
})
}
break;
// 是否靜音
case 'muted':
audio.muted = !audio.muted;
//為true,則是靜音模式
if (audio.muted) {
this.setState({
openMuted: true,
volume: 0
});
} else {
this.setState({
openMuted: false,
volume: 100
});
}
break;
// 調節音量
case 'changeVolume':
/**
* muted=true開啟靜音模式,muted=false開啟聲音
* @type {number}
*/
audio.volume = e.target.value / 100;
this.setState({
volume: e.target.value,
});
//如果聲音為0,開起靜音
if (e.target.value <= 0) {
audio.muted = true;
this.setState({
openMuted: true
})
} else if (e.target.value >= 0) {
audio.muted = false;
this.setState({
openMuted: false
})
}
break
}
}
}
componentDidMount() {
}
render() {
const {src} = this.props;
return (
<div className="audioBox">
<audio ref="audio"
src={src}
preload={true}
onCanPlay={() => this.controlAudio('allTime')}
onTimeUpdate={(e) => this.controlAudio('getCurrentTime')}
>
音樂播放器
</audio>
<i className={this.state.isPlay ? 'pause' : 'play'}
onClick={() => this.controlAudio(this.state.isPlay ? 'pause' : 'play')}
>
{
this.state.isPlay ? <Icon className="pause-btn" type="pause"/> :
<Icon className="play-btn" type="caret-right"/>
}
</i>
<span className="current">
{
this.millisecondToDate(this.state.currentTime) + '/' + this.millisecondToDate(this.state.allTime)
}
</span>
<input type="range"
className="time"
min="0"
step="0.01"
max={this.state.allTime}
value={this.state.currentTime}
onChange={(e) => this.controlAudio('changeCurrentTime', e)}
/>
<i className={this.state.openMuted ? 'mute' : 'nomute'}
onClick={() => this.controlAudio('muted')}
>
{
this.state.openMuted ? <Icon className="nomute-btn" type="check"/> :
<Icon className="mute-btn" type="close"/>
}
</i>
<input type="range"
className="volume"
min="0"
step="1"
max="100"
onChange={(e) => this.controlAudio('changeVolume', e)}
value={this.state.openMuted ? 0 : this.state.volume}
/>
</div>
)
}
}
const mapStateToProps = (state) => {
return {}
};
const mapActionCreators = {};
export default connect(mapStateToProps, mapActionCreators)(RecordAudio);
HTML 5 視頻/音頻參考手冊
HTML5 聲音引擎 Howler.js
MDN audio
基於 react 的 audio 組件
HTML5 Audio 的兼容性問題和優化
html5 audio 音頻播放全解析
音頻 API => AudioContext