在写实时聊天的页面的时候,有一个需求是点击完第一条开始播放后,后面如果没有播放就需要连续的往后播。新的消息来了之后需要自动播放;
由于ios的安全机制问题。不允许audio和video自动播放,所以想要获取页面上的audio标签然后给src值,然后使用自动播放那是实现不了的,即使给play()也是播放过不了;
解决方法是直接创建一个audio对象,当时问题是iOS也是不允许主动创建对象的,所以需要一个手动创建,可以选择全页面触发等
var Xut = {};
var isAudio = false;
var audioOnce = null;
var chatid = '';
var fixaudio = function() {
if (!isAudio) {
isAudio = true;
Xut.newaudio = new Audio();
document.removeEventListener('touchstart', fixaudio, false);
}
};
document.addEventListener('touchstart', fixaudio, false);
只要碰到页面就创建的了一个audio对象,然后再像这个对象中添加src地址,然后使用play()就可以播放了
if (Xut.newaudio) {
audio = Xut.newaudio;
audio.src = url;
} else {
Xut.newaudio = new Audio();
audio = Xut.newaudio;
audio.src = url;
}
这样通过动态添加src,就可以实现循环播放了
var clickplaying = 0;
function toplay(list, index, allUrl,allMsgID,chatId) {
if (index > list.length - 1) {
clickplaying = 1;
return;
}
var icon = list[index].children[0];
var url = allUrl[index];
if (index === audioOnce) { //点击的是同一个
if (audio.paused) { //暂停状态
audio.autoplay = true;
audio.play();
icon.setAttribute('class', 'voice-icon played');
} else {
audio.pause();
icon.setAttribute('class', 'voice-icon paused');
}
} else { //点击的不是同一个
//其他暂停
toPause()
//储存播放后状态
var readId = window.localStorage.getItem(chatId)
if(readId){
var setReadId = readId.split(',')
setReadId.push(allMsgID[index]).toString()
}else {
var setReadId = [allMsgID[index]].toString()
}
window.localStorage.setItem(chatId,setReadId)
var setRead = document.getElementsByClassName('setread')
if(setRead[index].children[0]){
setRead[index].children[0].setAttribute('class', '')
}
audioOnce = index;
icon.setAttribute('id', 'anchor');
console.log(url);
console.log(Xut.newaudio);
if (Xut.newaudio) {
audio = Xut.newaudio;
audio.src = url;
} else {
Xut.newaudio = new Audio();
audio = Xut.newaudio;
audio.src = url;
}
audio.load();
audio.onloadstart = function() {
icon.setAttribute('class', 'voice-icon playloading');
};
audio.oncanplaythrough = function() {
icon.setAttribute('class', 'voice-icon played');
audio.autoplay = true;
audio.play();
};
audio.onended = function() {
icon.setAttribute('class', 'voice-icon paused');
toplay(list, index + 1, allUrl,allMsgID,chatId)
}
}
}
我这个地方使用的vue1.0写的。所以使用了watch来监听数据的变化,如果数据有变化,分别给每个页面的ui播放按钮绑定点击事件,并且如果没有播放的情况下,来的数据是音频,那么就自动播放
watch: {
talkList: function() {
var that = this;
var list = document.getElementsByClassName("voiceSize");
var listLength = this.talkList;
var allUrl = [];
var allSize = [];
var allMsgID = [];
for (j = 0; j < listLength.length; j++) {
if (listLength[j].MSG_TYPE == 'VOICE') {
this.showonce = 1;
allUrl.push(listLength[j].MEDIA_URL)
allSize.push(listLength[j].MEDIA_SIZE)
allMsgID.push(listLength[j].MSG_ID)
}
};
for (var i = 0, len = list.length; i < len; i++) {
list[i].style.width = size(parseFloat(allSize[i])) + '%';
list[i].onclick = (function(index) {
return function() {
toplay(list, index, allUrl,allMsgID,that.radioID)
}
})(i);
};
if(listLength.length){
if(listLength[listLength.length-1].MSG_TYPE == 'VOICE' && clickplaying==1){
toplay(list, list.length-1, allUrl,allMsgID,that.radioID)
}
}
},
rightTalkList:function () {
this.rightScroll()
}
},
当然点击不同的播放按钮的其它的都应该暂停,其实这里只需要换一下页面上的显示而已,因为页面中就只有一个audio标签,所以点击其它的不存在暂停一说,src替换了就不可能还会播放了。
//点击其他播放按钮暂停时页面状态显示
function toPause() {
var icon = document.getElementsByClassName('voice-icon')
for (n = 0; n < icon.length; n++) {
icon[n].setAttribute('class', 'voice-icon paused');
icon[n].removeAttribute('id')
}
}
页面html代码也贴出来吧,方便理解
<div v-if="item.MSG_TYPE=='VOICE'">
<div class="line talk voiceSize">
<div class="voice-icon paused">
<div></div>
</div>
<em class="setread">
<i v-if="item.READ" class="unread"></i>
</em>
</div>
<span class="voice-time">{{item.MEDIA_SIZE | ceil}}</span>''
</div>
css代码
.voice-icon {
display: inline-block;
font-family: "Ionicons";
height: 20px;
width: 20px;
position: relative;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
text-rendering: auto;
line-height: 1;
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
&.paused{
height: 20px;
width: 20px;
border: 2px solid #4cd676;
border-radius: 50%;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
box-sizing: border-box;
}
&.paused:before {
content: '';
height: 0;
width: 0;
display: block;
border: 5px transparent solid;
border-right-width: 0;
border-left-color: #4cd676;
position: absolute;
top: 4px;
left: 6px;
}
&.played{
height: 20px;
width: 20px;
border: 2px solid #4cd676;
border-radius: 20px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
box-sizing: border-box;
}
&.played:before {
content: '';
height: 10px;
width: 2px;
display: block;
background: #4cd676;
position: absolute;
top: 4px;
left: 5px;
}
&.played:after {
content: '';
height: 10px;
width: 2px;
display: block;
background: #4cd676;
position: absolute;
top: 3px;
left: 9px;
}
&.playloading {
transition: opacity .25s linear;
opacity: 1;
}
&.playloading>div {
background-color: #fff;
border-radius: 100%;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
border: 2px solid red;
border-bottom-color: transparent;
height: 20px;
width: 20px;
background: transparent !important;
display: inline-block;
-webkit-animation: rotate 0.75s 0s linear infinite;
animation: rotate 0.75s 0s linear infinite;
}
ui效果是
还有一个红色的loading旋转动画。不好截图,脑补一下就好了