原⽣js实现歌词滚动以及卡拉OK效果
【歌词滚动效果】
滚动歌词⽐较常见的⼀种歌词显⽰⽅式,今天我们来讨论如何通过原⽣js来完成⼀个简单的滚动歌词实现。
⼀般来说,滚动歌词有如下⼏项需求:
1. 歌词在⼀个矩形区域内显⽰
2. 当前歌词⾏⾼亮
3. 在矩形显⽰区域中部固定位置显⽰当前歌词⾏
4. 当前歌词⾏切换到下⼀⾏时,下⼀⾏歌词⾼亮,并逐步移动到当前歌词⾏位置
5. 初始显⽰时歌词第⼀⾏顶住显⽰区域,当前歌词⾏未到达显⽰矩形区域的中部固定⾼亮位置时,不需要移动
6. 歌词尾⾏到达显⽰区域后,不需要移动
7. ⽤户可通过⿏标或者滚动条滚动歌词
8. ⽤户滚动歌词后,若当前歌词⾏被移动到矩形显⽰区域外,下⼀⾏歌词需定位到当前歌词⾏位置
其中需求5, 6通过图详述表⽰如下(黄⾊表⽰歌词容器,绿⾊表⽰歌词容器显⽰区域)
明确需求后,我们可以着⼿分析和实现了。如下图所⽰(我们假设⾼亮歌词固定位置在图中所⽰位置),我们通过设置歌词容器的scrollTop属性来上下移动歌词
在显⽰区域的位置。
通常情况下,我们的⽬标srollTop要求满⾜:
scrollTop = offsetTop(lineno) – 2/5*clientHeight
但是根据需求5、6,我们需要满⾜
0 <= scrollTop(lineno) <= scrollHeight – clientHeight
替换进去,得倒如下限制条件:
2/5*clientHeight <= scrollTop(lineno) <= scrollHeight – 3/5*clientHeight
⽤代码实现获取⽬标scrollTop:
var _scrollTop;
if (_ep.offsetTop < __eul.clientHeight*2/5){
_scrollTop = 0;
} else if (_ep.offsetTop > (__eul.scrollHeight - __eul.clientHeight*(3/5))){ _scrollTop = __eul.scrollHeight - __eul.clientHeight;
} else {
_scrollTop = _ep.offsetTop - __eul.clientHeight*2/5;
}
通过延时递归来实现当前歌词⾏滚动⽬标位置的动画效果
__scroll = function(_crt, _dst, _step){
if(Math.abs(_crt - _dst) < _step){
return;
}
if(_crt < _dst){
__eul.scrollTop += _step;
html滚动效果代码_crt += _step;
} else {
__eul.scrollTop -= _step;
_crt -= _step;
}
setTimeout(__scroll.bind(this, _crt, _dst, _step), __freq);
};
完整实现如下:
var __freq = 30; // 滚动频率(ms)
var __fraction = 2/5; // ⾼亮显⽰⾏在歌词显⽰区域中的固定位置百分⽐
/**
* 当前歌词⾏(lineno)滚动
*/
var __go = function(_lineno){
var _time;
if (_lineno === 0) {
_time = __lis[_lineno].offset;
} else {
_time = __lis[_lineno].offset - __lis[_lineno-1].offset;
}
var _timer = setTimeout(__go.bind(this, _lineno+1), _time);
// ⾼亮下⼀⾏歌词
if (_lineno > 0) {
__eul.children[_lineno-1].setAttribute("class", "");
}
var _ep = __eul.children[_lineno];
_ep.setAttribute("class", "z-crt");
// 满⾜需求5,6
var _scrollTop;
if (_ep.offsetTop < __eul.clientHeight*__fraction){
_scrollTop = 0;
} else if (_ep.offsetTop > (__eul.scrollHeight - __eul.clientHeight*(1-__fraction))){ _scrollTop = __eul.scrollHeight - __eul.clientHeight;
} else {
_scrollTop = _ep.offsetTop - __eul.clientHeight*__fraction;
}
// 如⽤户拖动滚动条导致当前显⽰⾏超出显⽰区域范围,下⼀⾏直接定位到当前显⽰⾏if (__eul.scrollTop > (_scrollTop + __eul.clientHeight*__fraction)
|| (__eul.scrollTop + __eul.clientHeight*__fraction) < _scrollTop){
|| (__eul.scrollTop + __eul.clientHeight*__fraction) < _scrollTop){
__eul.scrollTop = _scrollTop;
} else { // 单⾏滚动
// 获取滚动步长
var _step = il(Math.abs(__eul.scrollTop - _scrollTop)/(_time/__freq));
__scroll(__eul.scrollTop, _scrollTop, _step);
}
};
/**
* 歌词单⾏滚动实现
*/
__scroll = function(_crt, _dst, _step){
if(Math.abs(_crt - _dst) < _step){
return;
}
if(_crt < _dst){
__eul.scrollTop += _step;
_crt += _step;
} else {
__eul.scrollTop -= _step;
_crt -= _step;
}
setTimeout(__scroll.bind(this, _crt, _dst, _step), __freq);
};
__go(0);
附件demo可在chrome中运⾏
【卡拉OK效果】
卡拉OK桌⾯歌词⾃从诞⽣以来⼀直⼴受⾳乐爱好者的欢迎,⼏乎成为众多PC端⾳乐软件标准配置。
桌⾯歌词的⼀般表现效果如下(由于ks只能上传10FPS GIF图,所以下图动画效果略有卡顿),同时⽤户可以根据⾃⼰喜好设置显⽰⽅式(单⾏,多⾏)、字体、颜⾊、透明度等,此外还提供了歌词窗⼝锁定等功能。
桌⾯歌词的诞⽣要归功于windows2000开始ms开放的layered window解决⽅案,它为应⽤开发者提供了开发异形窗⼝功能强⼤的API。⾳乐软件开发者⽤这些API开发出了桌⾯歌词,此后长久以来桌⾯歌词的实现原理都不尽相同,主要有如下两个步骤:
1. GDI/GDI+绘制
2. layered window输出
那么有没有其他实现桌⾯歌词的⽅法呢? layered window作为异形窗⼝唯⼀的解决⽅案我们⽆法绕过去,但是显然直接操作GDI/GDI+不是绘制歌词的唯⼀⽅法,今天我们就来看通过浏览器离屏渲染绘制卡拉OK歌词的实现⽅法。
要浏览器实现绘制,⾃然就要⽤到html/css/js。虽然css3.0提供了⼀系列动画功能,但是我们很快发现只靠css⽆法实现卡拉OK歌词效果的动画。那么如何实现呢,我们最终到⼀种⽅法:镂空字体+背景⾊推进⽅式,如下:
采⽤上述⽅法,我们有两种实现⽅案可以选择:
1.⼀⾏歌词设置⼀个背景,歌词推进时将红⾊背景从左逐步推进。如下图
这是⼀种⽐较直观和好理解⽅式,但是在实现时遇到如下两个问题:
1)性能损失:js每次修改背景页⾯需要重新渲染整⾏歌词,性能有所损失,特别是在pc端混合应⽤中采⽤离屏渲染模式⽤该⽅案实现桌⾯歌词的时候,
性能损失较为明显。
2)实现复杂度:在固定刷新频率下,推进量和时间计算较为复杂。
2.每个字单独设置背景,在这个字所在的时间段内,只完成该字背景的推进,如下图。
该⽅案下,js每次修改背景实现推进时,页⾯只需要渲染单个字所在的区域,降低了性能损失。在实
现复杂度上,由于处理的对象粒度变⼩了,相当于简化了处理对象的⾏为模式,因此实现难度也有所降低(虽然还是有点复杂),具体的实现这⾥不做介绍,感兴趣的可以查阅附件代码。代码可以直接通过chrome打开运⾏。
⾄于如何将上述html+css+js实现的卡拉OK歌词效果应⽤到桌⾯歌词中,实现原理可以参阅⽂章 。前端组⽬前正在实现PC混合应⽤容器框架,届时可以直接引⼊,并通过js实现窗⼝开关、移动、锁定等等功能。
性能问题
layered window⽅案中存在⼀个对应⽤性能影响较⼤的⼀个限制因素:每次需要更新窗⼝时,都要更新整个窗⼝,⽽不能更新局部。如果我们更新频率过⾼,会导致性能出现明显下降。正因为如此,我们没有采⽤按像素推进的⽅式,⽽采⽤了定时刷新模式。这样⼀来我们可以通过调节刷新频率满⾜动画平滑度(⽤户体验)和应⽤性能之间的平衡关系,经过测试我们发现30ms左右⽐较合适(这个值可以开放给⽤户根据⾃⾝需求进⾏配置)。
以上介绍的通过浏览器离屏渲染实现桌⾯歌词的⽅案适合于应⽤了混合框架的⾳乐软件,因为需要内置⽀持离屏渲染浏览器引擎,所以单独⽤于实现桌⾯歌词是不合适的。不过鉴于⽬前云终端应⽤开发模式,市场上⼤部分pc⾳乐软件都内置了浏览器引擎。应⽤这种⽅式,将极⼤的提升开发维护效率并
降低相应的成本。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论