放一个歌词同步的JS UI
2021年1月15日 | by tgcode
很久没发文,一直想写点东西,整理整理这阵子的心得,很多笔记都在整理中。
最近给公司编写的一个JS UI,用于歌词同步,整理一下放出来,
核心脚本只负责处理lrc格式的歌词和呈现,并提供同步功能。
外部呈现等均可以良好定制。
基本调用如下:
var lrc=new LRC({lyricTable:obj,lyricWrapper:obj,curRowClassName:’xx’,lyric:’xxx’,separator:’
‘});
if(lrc.IsLyricValid()) lrc.DoSync(60);
DoSync(t)用于同步,参数t为当前播放进度,从播放器获得。
IsLyricValid()返回歌词是否合法的LRC格式。
贴出代码,附件下载中包含2个定制示例。代码在FF下跑不了,因为音乐播放插件跑不了~


<!–
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
–>1/**//*
2*@author:huangxu
3*@date:2008-11
4*@site:http://wsky.cnblogs.com
5*@descript:syncdisplaythelyric
6*@usage:
7*//importlrc.css
8*varlrc=newLRC({lyricTable:obj,lyricWrapper:obj,curRowClassName:’xx’,lyric:’xxx’,separator:’
‘});
9*if(lrc.IsLyricValid())lrc.DoSync(60);
10*
11*@note:内部变量前缀lrc_,普通变量i,ii,index,arg..
12*/
13
14LRC=function()
{this.initialize.apply(this,arguments);}
15LRC.prototype=
{
16arrLyricTime:[],
17arrLyric:[],//全局可用,必须执行初始化
18initialize:function(arg)
{
19//私有
20this.lyricTable=arg.lyricTable;//目标歌词table
21this.lyricWrapper=arg.lyricWrapper;//目标歌词容器div
22this.curRowClassName=arg.curRowClassName;//选择行css样式名
23this.separatgcodetor=arg.separator;//歌词行分隔符如:
24//执行初始化
25this.arrLyricTime=[];
26this.arrLyric=[];
27this.initArray(arg.lyric);
28this.arrLyricTime=this.sort(this.arrLyricTime);
29this.setLyricTable(this.arrLyric);
30},
31initArray:function(lyric)
{
32varlrc_re=newRegExp(‘[[0-9:.]*]‘,‘g‘);//g全局标志,获取所有匹配结果必须
33varlrc_arr=lyric.split(this.separator);
34varlrc_temp=0;
35varlrc_filter=0;//无效行过滤标记
36for(vari=0;ilrc_arr.length;i++)
{
37varlrc_txt=lrc_arr[i].replace(/[[wW]*]/g,”).Trim();//addtolyrictextarray
38if(lrc_txt==”)
{
39lrc_filter++;
40continue;
41}
42this.arrLyric[i–lrc_filttgcodeer]=lrc_txt;
43while((lrc_result=lrc_re.exec(lrc_arr[i]))!=null)
{
44varlrc_second=this.parseSecond(lrc_result.toString().replace(/[|]/g,”));
45if(!isNaN(lrc_second))
46this.arrLyricTime[lrc_temp++]=(i–lrc_filter)+‘|‘+lrc_second;//arrLyricTime格式为”行号|秒”,如:1|50,2|60
47}
48}
49},
50/////////////////////////////////////////////////////////////////////////////////////////
51//公开函数
52//IsLyricValid()判断是否合法lrc歌词
53//DoSync()定位歌词
54/////////////////////////////////////////////////////////////////////////////////////////
55IsLyricValid:function(arrLyricTime)
{
56returnthis.arrLyricTime.length>0;
57},
58DoSync:function(curPosition)
{
59varlrc_times=this.arrLyricTime;
60for(vari=0;ilrc_times.length;i++)
{
61varlrc_arrPre=lrc_times[i].split(‘|‘);
62
63if(i==0&&curPositionlrc_arrPre[1])break;//防止抖动
64
65if(lrc_times[i+1]==undefined)
{
66this.setRow(lrc_arrPre[0]);
67break;
68}
69
70varlrc_arrNext=lrc_times[i+1].split(‘|‘);
71if(curPosition>=lrc_arrPre[1]&&curPositionlrc_arrNext[1])
{
72this.setRow(lrc_arrPre[0]);
73break;
74}
75}
76},
77/////////////////////////////////////////////////////////////////////////////////////////
78//以下为内部辅助函数
79/////////////////////////////////////////////////////////////////////////////////////////
80parseSecond:function(time)
{
81try
{
82varlrc_arr=time.split(‘:‘);//time格式为时间格式00:00
83returnparseInt(lrc_arr[0])*60+parseFloat(lrc_arr[1]);
84}catch(ex)
{
85return0;
86}
87},
88setLyricTable:function(arrLyric)
{
89this.lyricWrapper.scrollTop=0;//滚动条置顶
90
91if(this.lyricTable.rows.length>0)
{
92this.clearTable(this.lyricTable);
93}
94for(vari=0;iarrLyric.length;i++)
{
95varlrc_tr=this.lyricTable.insertRow();
96varlrc_cell=lrc_tr.insertCell(0);
97lrc_cell.innerHTML=arrLyric[i];
98}
99},
100clearTable:function(lyricTable)
{
101varlrc_rowNum=lyricTable.rows.length;
102for(vari=0;ilrc_rowNum;i++)
{
103lyricTable.deleteRow(i);
104lrc_rowNum=lrc_rowNum–1;
105i=i–1;
106}
107},
108setRow:function(index)
{
109this.setRowClass(index);
110this.setScroll(index);
111},
112setRowClass:function(index)
{
113varlrc_rows=this.lyricTable.rows;
114for(vari=0;ilrc_rows.length;i++)
{
115lrc_rows[i].className=”;//TODO:直接添加样式至元素,防止外部css干扰
116}
117lrc_rows[index].className=this.curRowClassName;
118},
119setScroll:function(index)
{
120this.lyricWrapper.scrollTop=this.lyricTable.rows[index].offsetTop–this.lyricWrapper.offsetHeight/3;
121},
122sort:function(arrLyricTime)
{
123for(vari=0;iarrLyricTime.length–1;i++)
{
124for(varii=i+1;iiarrLyricTime.length;ii++)
{
125varlrc_cur=parseFloat(arrLyricTime[i].split(‘|‘)[1]);
126varlrc_next=parseFloat(arrLyricTime[ii].split(‘|‘)[1]);
127if(lrc_cur>lrc_next)
{
128varlrc_temp=arrLyricTime[i];
129arrLyricTime[i]=arrLyricTime[ii];
130arrLyricTime[ii]=lrc_temp;
131}
132}
133}
134returnarrLyricTime;
135}
136}
137
138
139/////////////////////////////////////////////////////////////
140//外部函数
141/////////////////////////////////////////////////////////////
142String.prototype.Trim=function()
143{
144returnthis.replace(/^s*|s*$/g,“”);
145}
146
Demo下载:http://files.cnbltgcodeogs.com/wsky/lrcUI_wsky.rar
首先要感谢诸多朋友对鄙人的一些拙见表示关注,不少朋友反应上一篇的分享有点意犹未尽,我的理解可能是大家觉得我写的不够快。呵呵…由于系统整理相关资料需要一段时间,另外要尽量保持原创的风格。所以周期会稍微长一点点,但我尽量会一周写1-2篇相关专题。 上篇看到不少…