最近在做一个摇一摇抽奖小项目,碰到了要在抽奖不同阶段响起该阶段声音。“开奖部分”,“摇晃”,“获奖”,“未获奖”四个阶段,响起的声音各不同。
在iOS5上,音频文件只能从用户触发的触摸(单击)事件加载,如果在 HTML 标记中使用了 autoplay 属性,那么 Safari 将会忽略这个属性,并且不会在加载页面时播放此文件,对于 preload 属性,Safari 同样会忽略。
唯一能解决的就是用户进入页面是,让用户触发 touch 事件:
$("#choujiangBtn").unbind().bind("touchstart", function() {
audioData.firstRock = true; //点击抽奖按钮的时候,把audioData.firstRock 设为true,表示可以摇晃手机进行抽奖
audioData.audio.load();
playAudio();
});
audioData是一个存储Audio的对象:
audioData = {
audio: new Audio("soundeff.mp3"),
firstRock: false,
start: {
startTime: 1,
length: 4
},
shake: {
startTime: 6,
length: 3
},
win: {
startTime: 12,
length: 3
},
miss: {
startTime: 16,
length: 1
}
}
在这里使用 audio sprite,将所有的音频综合到一个单音频流中,然后播放此流的各个部分。是因为iOS Safari 中的 HTML5 媒体元素都是单例的,一次只能播放一个 HTML5 音频(和 HTML5 视频)流。
播放事件:
function playAudio() {
clearInterval(audioData.timer);
audioData.audio.addEventListener("canplaythrough", function() {
audioData.audio.play();
//重复播放开始部分,后面的几个阶段只播放一次
audioData.timer = setInterval(function() {
if (audioData.audio.currentTime >= (audioData.shake.startTime)/2&&audioData.audio.currentTime<audioData.shake.startTime) {
audioData.audio.currentTime = audioData.start.startTime;
}
}, 3000);
}, false);
}
播放 winAudio 同理。需要注意的是,更改 currentTime 并不是百分百正确的。假设 currentTime 设为 6.5,而实际得到的却是 6.7。每个 audio sprite 之间需要少量的空间,以避免寻找到另一个 sprite 的头部。
在访问任何 audio sprite 之前,务必确保整个音频流已加载,因为如果音频流没有完全加载,那么在想要访问已加载的流的任何一个部分时,那么这个流需要进行缓冲,而且还会在流加载过程中发生延时。
当摇动手机事件:
window.addEventListener('devicemotion', function() { if (audioData.firstRock) { var acceleration = event.accelerationIncludingGravity; // 获取设备的加速度 x = acceleration.x; // 获取加速度的x轴,用于计算水平水平加速度 y = acceleration.y; // 获取加速度的y轴,用于计算垂直方向的加速度,同时计算正玄值 // 计算当前的加速度是否大于默认加速度 if (Math.abs(x - lastX) > speed || Math.abs(y - lastY) > speed) { audioData.audio.currentTime = audioData.shake.startTime; //更改当前播放时间,播放摇动部分 getValue(); //调用抽奖接口,判断是否中奖 audioData.firstRock = false; //把audioData.firstRock改为false状态,不可再次摇动; clearInterval(audioData.timer); //清除循环播放开始部分声音 } // 重新记录最后一次值,作为下一次开始坐标 lastX = x; lastY = y; }; }, false);
根据getValue()得到的值判断是否中奖:
if (num) { audioData.audio.currentTime = audioData.win.startTime; //更改当前播放时间,播放中奖部分 //播放完中奖声音片段,终止播放,防止继续播放未中奖声音片段 setTimeout(function() { audioData.audio.pause(); }, audioData.win.length); showPage2(num); //进入中奖页面 } else { audioData.audio.currentTime = audioData.miss.startTime; //更改当前播放时间,播放未中奖部分 showPage3(num); //进入未中奖页面 };
如果未中奖,点击再抽一次按钮,把audioData.firstRock 设为 true;进入首页,重新摇动,进行再次抽取。
如果中奖,点击填写信息按钮,进入个人信息填写界面,完成抽奖。