29

我有一个以链接形式呈现的音频文件列表和一个<audio>html5 播放器。每个链接都会调用一个函数,该函数会更改以下<source>标签的 src <audio>

<audio controls="controls" preload="none">
  <source type="audio/mpeg" src="{{selectedSongPath}}"/>
</audio>

...

<div class="songEntry" ng-repeat="song in songs">
  <a href="" ng-click="songSelect(song.path)">{{song.name}}</a>
</div>

...

$scope.songSelect = function(songPath) {
    $scope.selectedSongPath = songPath;
}

我可以看到 src 发生变化,但没有播放任何内容。路径还可以;如果我用其中一条路径初始化 src,播放器就会工作。

我究竟做错了什么?

4

11 回答 11

25

这是几个角度方法:

1) 使用 ng-src= 而不是 src=

角度文档解释了为什么这样做:http://docs.angularjs.org/api/ng.directive: ngSrc

在编译阶段,angular 将扩展元素以包含正确的 src= 属性。

这将更改 HTML5 音频元素的 src 属性,但不幸的是,这还不足以播放新歌曲。您需要通过调用 .play() 方法来促使音频元素执行某些操作。

糟透了:(

沿着同样的路径进一步破解建议在控制器内部进行 DOM 操作。这通常表明这是错误的解决方案。

更好的解决方案是使用服务!

2)使用角度服务的音频

// Define a simple audio service 
mpApp.factory('audio',function ($document) {
  var audioElement = $document[0].createElement('audio'); // <-- Magic trick here
  return {
    audioElement: audioElement,

    play: function(filename) {
        audioElement.src = filename;
        audioElement.play();     //  <-- Thats all you need
    }
    // Exersise for the reader - extend this service to include other functions
    // like pausing, etc, etc.

  }
});

现在,在你的控制器中,你可以注入“音频”,然后做任何你需要做的事情。

例如:

function myAstoundingAudioCtrl($scope, audio) { //<-- NOTE injected audio service

    $scope.songSelect = function(songPath) {
        audio.play(songPath);    //     <---  Thats All You Need !
    }
}

您现在可以将“音频”作为参数添加到需要能够更改音乐的任何控制器,并使用此处定义的相同 API 调用。

作为“服务”,整个应用程序只有一个实例。所有对“音频”的调用都指向同一个对象。对于 Angular 中的所有服务都是如此。正是我们在这种情况下所需要的。

该服务在应用程序的根文档上创建一个不可见的 HTML5 元素,因此无需在任何地方的视图上添加标签。这具有在用户导航到不同视图时保持歌曲播放的额外好处。

有关$document 服务的定义,请参见 http://docs.angularjs.org/api/ng .$document。

希望对伴侣有帮助:)

于 2013-05-23T18:54:26.877 回答
19

即使在使用 $sce.trustAsResourceUrl 之后,我也遇到了同样的问题,然后我意识到问题出在 HTML 上。源应该放在音频标签本身:

<audio controls data-ng-src="{{yourTrustedUrl}}" ></audio>
于 2014-10-28T09:54:45.257 回答
5
<audio ng-src="{{getAudioUrl()}}" audioplayer controls></audio>

$scope.getAudioUrl = function() {
return $sce.trustAsResourceUrl('your url');
};

这对我有用,你需要净化你

于 2014-06-15T16:27:28.187 回答
4

ngSrc 不适用于 AngularJS 中的视频,仅适用于图像。我的解决方案是:

在视图中:

        <video controls="controls" name="Video Name" ng-src="{{getVideoUrl()}}"></video>

在控制器中:

  $scope.getVideoUrl=function(){
        return $sce.trustAsResourceUrl("media/"+$scope.groupedProjList[$scope.routeId].CONTACTNAME+".mp4");
   };

用你的替换我的网址:

$sce.trustAsResourceUrl('your Url');

不要忘记添加$sce到您的模块:

angular.module('myApp.controllers', [])
  .controller('MyCtrl1',  function($scope,$http,$routeParams,$sce) {
于 2016-02-21T10:51:50.047 回答
2

我在使用下拉选择菜单加载视频源时遇到了类似的问题。我找到$scope.$apply();就是我需要添加的所有内容。还没有时间获取您的代码并测试此实现,但我建议您尝试一下:

$scope.songSelect = function(songPath) {
    $scope.selectedSongPath = songPath;
    $scope.$apply();
}

$scope.$apply()关于处理错误的使用存在一些争议。我相信正确的实现实际上如下:

$scope.songSelect = function(songPath) {
    $scope.$apply(function() {
        $scope.selectedSongPath = songPath;
    });
}

这应该可以更好地应对,如果songPath返回未定义,这应该会更好地应对;唉,我找不到我学到这个技巧的链接。如果我这样做,我会将其作为对此答案的评论发布。

希望这可以帮助 :)

于 2013-08-03T11:31:04.690 回答
1

你也可以使用这个:

<div ng-bind-html-unsafe="audioPlayer"></div>

在您的控制器上:

$scope.audioPlayer="<br /><audio controls><source src=\""+ audiosource + "\" type=\"audio/mpeg\"> Your browser does not support the audio element. </audio>"

注意力:

仅当 ngBindHtml 指令过于严格并且您绝对信任要绑定的内容的来源时,才应使用此指令。

更多在这里

于 2013-05-30T08:02:23.857 回答
1

@SteveOC 64 的方法处理创建音频的新实例。如果您已经有一个音频标签,例如

<audio id="audio" controls></audio>

你可以试试下面的代码

    app.factory('audio', function($document) {
    var audioElement = $document[0].getElementById('audio');
    audioElement.autoPlay = true; // as per your requirement

    return {
      audioElement: audioElement,

      play: function(filename) {
        audioElement.src = filename;
        audioElement.play();
      },
      resume: function() {
        audioElement.play();
      },
      pause: function() {
        audioElement.pause();
      },
      stop: function() {
        audioElement.pause();
        audioElement.src = audioElement.currentSrc; /** http://stackoverflow.com/a/16978083/1015046 **/
      },
      incVol: function() {
        if (audioElement.volume < 1) {
          audioElement.volume = (audioElement.volume + 0.1).toFixed(2);
        }
        return audioElement.volume;
      },
      decVol: function() {
        if (audioElement.volume > 0) {
          audioElement.volume = (audioElement.volume - 0.1).toFixed(2);
        }
        return audioElement.volume;
      },
      timer: function(callback) {
        audioElement.ontimeupdate = function() {
          callback(audioElement.duration, audioElement.currentTime)
        };
      },
    }
  });

在注入audio工厂后在您的控制器中,您可以将其称为

 audio.play('/api/resource?resource=' + uri);

如果这是一个事件驱动的,例如在单击另一个元素时播放音频

$scope.$apply(function() {
   $scope.audioPlayer = true;
   audio.play('/api/resource?resource=' + uri);
   $scope.isAudioPlaying = true;
});

如果有人正在寻找视频工厂:

HTML

<video id="video" controls></video>

工厂

app.factory('video', function($document) {
       var videoElement = $document[0].getElementById('video');
       videoElement.autoPlay = true;
       return {
          videoElement: videoElement,
          play: function(filename) {
             videoElement.src = filename;
             videoElement.play();
          },
          resume: function() {
             videoElement.play();
          },
          pause: function() {
             videoElement.pause();
          },
          stop: function() {
             videoElement.pause();
             videoElement.src = videoElement.currentSrc; /** http://stackoverflow.com/a/16978083/1015046 **/
          },
          incVol: function() {
             if(videoElement.volume < 1) {
                videoElement.volume = (videoElement.volume + 0.1).toFixed(2);
             }
             return videoElement.volume;
          },
          decVol: function() {
             if(videoElement.volume > 0) {
                videoElement.volume = (videoElement.volume - 0.1).toFixed(2);
             }
             return videoElement.volume;
          },
          timer: function(callback) {
             videoElement.ontimeupdate = function() {
                callback(videoElement.duration, videoElement.currentTime)
             };
          },
       }
    });

您可以将其调用为video.play('/api/resource?resource=' + uri);

希望这可以帮助!

于 2014-10-15T04:08:39.390 回答
1

我找到的解决方案是从 ajax 调用获得视频网址后立即加载视频。

var video = angular.element('#video_id');
video.load();
于 2017-02-04T04:14:40.250 回答
0

从未尝试过使用audio标签,但src应该插值,所以它应该在{{}}.

<audio controls="controls" preload="none">
  <source type="audio/mpeg" src="{{selectedSongPath}}"/>
</audio>

你已经试过了吗?

于 2013-03-18T20:07:43.160 回答
0

更改 src 后,您还必须加载该文件,因此请尝试在以下内容songselect之后添加到您的函数$scope.selectedSongPath = songPath;中:

$scope.load();

我不知道你的情况是什么 $scope ,但该load()方法应该在你的音频标签的对象内执行。在简单的 JS 中,它看起来像这样:

<audio id="audio-tag" controls="controls" preload="none"> //need the ID to get element
    <source type="audio/mpeg" src="{{selectedSongPath}}"/>
</audio>
....
$scope.selectedSongPath = songPath; //you're changing the src
document.getElementById("audio-tag").load(); //here you load the file (you need equivalent in your framework)

希望能帮助到你。

于 2013-03-18T20:18:26.343 回答
0

我之前使用 ngAudio 并且面临一次播放多个音频的问题。当尝试使用 HTML5 音频标签,而不是将音频和源作为 2 个标签时,只有 1 个标签解决了我的问题。

<audio controls ng-src='{{trusted_url }}'></audio>

于 2015-09-15T06:29:43.307 回答