我最初注意到與timeupdate
事件只在Firefox上出現的這個問題,但發現它適用於其它事件偵聽器,以及(到目前爲止我已經看到它在canplay
)音頻事件監聽器入門稱爲非停止
基本上,我有一個在角度指令內創建的元素;我綁定功能ontimeupdate,甚至當currentTime的值是0
代碼小結該事件被炒魷魚馬不停蹄:
// angular directive controller function
...
DOMAudioObject = createAudioObject(src);
DOMAudioObject.audio.ontimeupdate = onTimeUpdate;
function createAudioObject(src) {
return {
audio: new Audio(src),
playback: $scope.playback,
name: $scope.name
};
}
function onTimeUpdate() {
var currentTime = DOMAudioObject.audio.currentTime;
console.log(currentTime);
$scope.currentTime = currentTime;
$scope.audio.currentTime = currentTime;
$scope.$apply();
}
全部控制器代碼:
function audioCtrl($scope) {
// private reference to the DOM object that plays the audio
var DOMAudioObject,
watchers = {unbind: {}};
// register watchers once the model is available, we need at least the id field
watchers.unbind.model = $scope.$watch('model', init);
// remove watchers when the user navigates away
$scope.$on('$destroy', destroyWatchers);
function applyAudioPropertiesAsync() {
DOMAudioObject.audio.volume = $scope.volume;
DOMAudioObject.audio.currentTime = $scope.currentTime;
$scope.audio.duration = DOMAudioObject.audio.duration;
}
function applyAudioMetaProperties() {
$scope.audio = $scope.audio || {};
$scope.audio.id = $scope.model.id;
$scope.audio.playback = $scope.playback;
$scope.audio.name = $scope.model.name;
$scope.audio.volume = $scope.volume;
$scope.audio.currentTime = $scope.currentTime;
$scope.audio.duration = DOMAudioObject.audio.duration || 0;
}
// fired when the audio object has been loaded from src
function bindAudio(src, oldSrc) {
if (src === undefined) {
return;
}
// now safe to register watchers since they rely on the audio object
registerWatchers();
// if there is already a stored audio object associated with this visual, use it
DOMAudioObject = $audio.get($scope.model.id);
// audio src has been updated, reflect by pausing and creating a new audio object
if (oldSrc && src !== oldSrc) {
$scope.playback.play = false;
$scope.currentTime = 0.0;
pause(DOMAudioObject);
DOMAudioObject = null;
}
// create a new audio object or use stored values instead of reinitializing each time
if (!DOMAudioObject) {
DOMAudioObject = createAudioObject(src);
// set in $audio service for persistence across views and controllers
$audio.set($scope.model.id, DOMAudioObject);
} else {
$scope.playback = DOMAudioObject.playback || $scope.playback;
$scope.currentTime = DOMAudioObject.audio.currentTime || $scope.currentTime;
$scope.volume = DOMAudioObject.audio.volume || $scope.volume;
}
// only bind meta properties, binding actual Audio object causes problems in some browsers
applyAudioMetaProperties();
// add values that must be calculated after initial load
DOMAudioObject.audio.oncanplay = applyAudioPropertiesAsync;
// tell playback progress indicator to move on timeupdate event by firing a digest cycle
DOMAudioObject.audio.ontimeupdate = onTimeUpdate;
// tell animate directive to stop scrolling when the audio has ended
DOMAudioObject.audio.onended = onAudioEnded;
// tell parent this directive is ready when the audio has fully loaded
watchers.unbind.duration = $scope.$watch('audio.duration', function (val) {
if (val > 0) {
$scope.$emit('audio.ready', {id: $scope.model.id, audio: $scope.audio});
watchers.unbind.duration();
}
});
}
// create a dom audio object
function createAudioObject(src) {
return {
audio: new Audio(src),
playback: $scope.playback,
name: $scope.model.name
};
}
function destroyWatchers() {
if (watchers.unbind.audio) {
watchers.unbind.audio();
}
if (watchers.unbind.playback) {
watchers.unbind.playback();
}
if (watchers.unbind.progress) {
watchers.unbind.progress();
}
if (watchers.unbind.volume) {
watchers.unbind.volume();
}
}
function init(visual) {
if (visual === undefined) {
return;
}
// prevent updates to visual model from rebinding audio
watchers.unbind.model();
// when the audio-src is available and fully loaded, create audio objects
watchers.unbind.audio = $scope.$watch('audioSrc', bindAudio);
}
function onAudioEnded() {
// ensure playback variables are updated
$scope.$apply($scope.playback.play = false);
$scope.currentTime = 0;
}
// timeupdate event to update scope attribute with that of the Audio object
function onTimeUpdate() {
var currentTime = DOMAudioObject.audio.currentTime;
$scope.currentTime = currentTime;
$scope.audio.currentTime = currentTime;
$scope.$apply();
}
// pause the current track
function pause(audio) {
if (audio) {
audio.audio.pause();
}
}
// play the current track
function play(audio) {
if (audio) {
audio.audio.play();
}
}
function registerWatchers() {
// allow audio to be toggled on/off
watchers.unbind.playback = $scope.$watch('playback.play', togglePlay);
// allow volume changes
watchers.unbind.volume = $scope.$watch('volume', updateVolume);
// allow seeking of audio
watchers.unbind.progress = $scope.$watch('currentTime', seek);
// update the name variable on the audio object so it reflects in global scope
watchers.unbind.name = $scope.$watch('model.name', applyAudioMetaProperties);
}
// move audio position pointer to a new place
function seek(val) {
var threshold = 1,
curr = DOMAudioObject.audio.currentTime;
if ((val >= curr + threshold) || (val <= curr - threshold)) {
DOMAudioObject.audio.currentTime = val;
}
}
// toggle play/pause
function togglePlay(val) {
if (val) {
play(DOMAudioObject);
$audio.setGlobal($scope.audio);
} else {
pause(DOMAudioObject);
}
}
// allow the volume to be changed, scope reference updates automatically (pass by reference)
function updateVolume(val) {
if (val) {
DOMAudioObject.audio.volume = val;
}
}
}
然後,當你的圖像中看到的,onTimeUpdate()函數不斷變得叫了一遍又一遍,即使currentT的價值IME處理不當改變(它是每個時間0)
再次,這僅發生在Firefox。 Chrome瀏覽器,Safari瀏覽器,甚至Internet Explorer的行爲都很好。我在Mac OS X 10.11埃爾卡皮坦運行Firefox 40.0.3,角1.4.6
有誰有一些洞察可能被這裏發生的一切,以及任何可能的解決方案來解決這個問題?
是否有可能以某種方式'DOMAudioObject.audio === $ scope.audio'?如果是這樣的話,我認爲FF可以在'currentTime'的'set()'中放置一個EventDispatcher,這是正常的行爲。解決方法就是簡單地'if(this!== $ scope.audio)$ scope.audio.currentTime = currentTime;' – Kaiido
我試着做你說的話,仍然沒有修復它。我甚至嘗試用angular.copy()包裝$ scope和DOMAudioObject之間的任何綁定,問題仍然存在。如果您有興趣查看,我確實更新了我的文章以提供更多控制器代碼 – jasonaibrahim