angular做个简单的音乐播放器
指令与服务
因为音乐播放器需要操纵DOM元素,所以不应该在控制器中直接操控,于是可以利用服务和指令来实现.这里利用指令来实现
模板样式
<div class="music-play">
<p>{{now_music.name}}</p>
<audio class="music_audio" ng-src="{{now_music.src}}"></audio>
<div class="bar " style="width: 100%">
<span class="bar-bg">
<span class="bar-on music-play-progress"></span>
</span>
</div>
<div class="music-play-ctrl">
<div class="btn-group">
<button class="btn btn-default" ng-click="musicPref()">
<span class="glyphicon glyphicon glyphicon-step-backward"></span>
</button>
<button class="btn btn-default" ng-click="musicPlay()">
<span class="glyphicon " ng-class="playClass?'glyphicon-pause':'glyphicon-play'"></span>
</button>
<button class="btn btn-default" ng-click="musicNext()">
<span class="glyphicon glyphicon glyphicon-step-forward"></span>
</button>
</div>
</div>
</div>
<ul class="list-group roomNumber">
<li class="list-group-item " ng-repeat="music in music_list ">
<div class="row">
<div class="col-sm-7" ng-click="play(music)" ng-class="now_music==music?'now_play':'ttt' ">{{music.name}}
</div>
</div>
</li>
</ul>
其中now_music为当前歌曲 为一个object;music_list为歌曲列表
写个指令
app.directive("musicPlayer", function ($timeout) {
return {
restrict: 'EA',
templateUrl: '/musicPlay.html',
controller: function ($scope) {
//数据交换操纵
},
link: function (scope, element, attr) {
//DOM操纵
}
指令这块写的不是太好 因为就算是DOM操纵也涉及到了一部分的数据交换,仅仅是把涉及到DOM操纵的数据交换放link里,毕竟link一但编译后就不变动了比如你在link里写个代码
$("p").html($scope.name)
然后在controller里写个定时器 每秒加1
$scope.name=0
$timeout(function(){
$scope.name++
},1000)
然后刷新下页面后,发现在p标签中有个0,但是一秒后这个0并不会变
controller数据交换
添加歌曲列表
$scope.$on("musicList", function (event,data) {
$scope.music_list = data
}
我采用的是广播的形式来获取歌曲列表 实际上也可以通过ajax获取后赋值,因为要拿到值后才能做剩下的动作 所以controller层的所有代码都在 $scope.$on里
设置当前歌曲时间信息
$scope.pointer = 0 //歌曲指针
$scope.now_music = $scope.music_list[$scope.pointer] //当前歌曲
//歌曲当前时间
$scope.progress_time = {
now: 0,
true_time: 0,
end: 0,
}
true_time用来判断歌曲剩下的时间
播放与暂停
//播放与暂停
$scope.musicPlay = function () {
//只有当歌曲触发了"canplay"事件才能点击
if ($scope.progress_time.end == 0) {
console.log("未准备")
return false
} else if ($scope.playClass) {
$scope.audio.pause();
$scope.playClass = false
$scope.clearAudioProgress();
console.log("暂停")
} else if ($scope.playClass == false) {
//获取歌曲当前时间
$scope.getNowTime()
$scope.progress_time.true_time = ($scope.progress_time.end - $scope.progress_time.now) * 1000
$scope.setAudioProgress($scope.progress_time.true_time)
$scope.audio.play();
$scope.playClass = true;
console.log("开始")
}
}
因为播放涉及到一个audio标签的事件也就是”canplay”,所以这里的播放暂停是针对 触发了canplay后的暂停与播放 什么意思呢?比如歌曲没触发canplay事件之前 暂停与播放都是返回false至于$scope.clearAudioProgress()和setAudioProgress()看下面代码当歌曲触发了canplay事件后会设置$scope.progress_time.endplayClass为播放按钮样式,
下一曲
//下一曲
$scope.musicNext = function () {
if ($scope.pointer >= $scope.music_list.length - 1) {
return false
}
//设置歌曲与进度条为初始状态
$scope.clearAudioProgress(true)
$scope.setNowTime(0)
$scope.pointer++
$scope.now_music = $scope.music_list[$scope.pointer]
}
先判断歌曲是否为列表最后一个歌曲了,如果不是那就设置一下进度条更新下now_music
上一曲
//上一曲
$scope.musicPref = function () {
if ($scope.pointer <= 0) {
return false
}
//设置歌曲与进度条为初始状态
$scope.clearAudioProgress(true)
$scope.setNowTime(0)
$scope.pointer--
$scope.now_music = $scope.music_list[$scope.pointer]
}
})
同 下一曲
link DOM操纵区
获取audio标签和进度条标签
//关于DOM操作都在这块
scope.audio = $(".music_audio")[0]
scope.audio_progress = $(".music-play-progress")[0];
触发了canplay事件
//当歌曲触发了canplay事件才能播放
$(scope.audio).on("canplay", function () {
//重置歌曲信息
scope.progress_time.now = scope.audio.currentTime = 0
scope.progress_time.true_time = 0
scope.progress_time.end = scope.audio.duration
//清除进度条
scope.clearAudioProgress()
scope.audio.play()
scope.playClass = true;
//设置进度条
scope.progress_time.true_time = (scope.progress_time.end - scope.progress_time.now) * 1000
scope.setAudioProgress(scope.progress_time.true_time)
scope.$apply()
})
清除进度条当前状态
//清除进度条当前状态
scope.clearAudioProgress = function (val) {
$(scope.audio_progress).stop(true)
if (val) {
$(scope.audio_progress).width(0)
}
}
传递了不为false的val会清除进度条 否则仅仅是停止进度条动画
进度条动画
//设置进度条
scope.setAudioProgress = function (time, cb) {
$(scope.audio_progress).stop(true)
$(scope.audio_progress).animate({
width: "100%"
}, time, function () {
scope.musicNext()
})
}
获取与设置歌曲当前时间
//获取歌曲当前时间
scope.getNowTime = function () {
return scope.progress_time.now = scope.audio.currentTime
}
//设置歌曲当前时间
scope.setNowTime = function (val) {
scope.progress_time.now = scope.audio.currentTime = val
}
后记
其实这个例子待改进的地方很多 在link区可以var一个object然后$scope.musicServer=object 返回一个object 这样就不会暴露很多的函数.