【问题标题】:Changing html5's source "src" attribute takes no effect wtih angularjs更改 html5 的源“src”属性对 angularjs 无效
【发布时间】:2013-03-07 07:37:05
【问题描述】:

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

<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,播放器就可以工作。

我做错了什么?

【问题讨论】:

  • 您找到解决此问题的方法了吗?我也有类似的问题。

标签: angularjs html5-audio


【解决方案1】:

这里有几个角度方法:

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。

希望对伴侣有帮助:)

【讨论】:

  • 这是一个很好的解决方案。我很感激你在最后解释了它是如何工作的!最佳答案
【解决方案2】:

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

<audio controls data-ng-src="{{yourTrustedUrl}}" ></audio>

【讨论】:

  • 对不起“我也是”,但我真的很想感谢你。我花了很多时间在这个问题上并变得疯狂。
【解决方案3】:
<audio ng-src="{{getAudioUrl()}}" audioplayer controls></audio>

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

这对我有用,你需要给你消毒

【讨论】:

    【解决方案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) {
    

    【讨论】:

      【解决方案5】:

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

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

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

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

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

      希望这会有所帮助:)

      【讨论】:

        【解决方案6】:

        你也可以这样用:

        <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 指令也使用该指令时,才应使用该指令 限制性,并且当您绝对信任内容的来源时 您正在绑定。

        更多here

        【讨论】:

          【解决方案7】:

          @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 factory 后,你可以像这样调用它

           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);

          希望这会有所帮助!

          【讨论】:

          • 你有没有机会使用 angularjs 处理 onended 事件?
          【解决方案8】:

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

          var video = angular.element('#video_id');
          video.load();
          

          【讨论】:

            【解决方案9】:

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

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

            你已经试过了吗?

            【讨论】:

            • 对不起,错字(我没有复制/粘贴)。是的,它在 {{}} 之间。已编辑。同样,src 正在改变,播放器没有响应@CaioToOn
            【解决方案10】:

            更改 src 后,您还必须加载该文件,因此请尝试在 songselect 之后添加以下内容:

            $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)
            

            希望对你有帮助。

            【讨论】:

            • 在我的例子中,ctrl 是整个 。无论如何,您建议的 $scope.load() 会引发异常:TypeError: Object # has no method 'load'。 @sobol6803
            • 您的简单 js 解决方案可以工作,谢谢。任何有棱角的解决方案可用..? “您的框架中需要等效项”是什么意思? @sobol6803
            • 我的意思是 document.get... 仅适用于您的情况。如果你使用 angularjs,你应该在这个框架中找到解决方案。所以在这种情况下我的回答只是给你一个提示,因为我不知道这个框架,我现在真的没有时间研究它,但是纯js中的方法绝对是load,你应该寻找它。也许,如果您的音频标签像您定义的 $scope (由ng-something)定义,然后使用 $audio.load() 或类似的东西?这是一个很长的镜头,但我现在无能为力。对不起。
            • 非常感谢,非常感谢您的帮助,但这只是一种解决方法:当我使用 document.get... 我需要点击某个链接两次才能加载播放器@sobol6803
            • 使用 load() 非常有帮助。非常感谢!
            【解决方案11】:

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

            &lt;audio controls ng-src='{{trusted_url }}'&gt;&lt;/audio&gt;

            【讨论】:

              猜你喜欢
              • 2012-10-09
              • 2014-02-01
              • 1970-01-01
              • 2023-03-12
              • 2013-02-24
              • 2021-11-24
              • 2015-04-02
              • 2021-09-09
              • 1970-01-01
              相关资源
              最近更新 更多