本文介绍如何使用JavaScript实现文字滚动效果,涵盖水平与垂直两种排列方式。通过解析CSS3的writing-mode属性,结合HTML结构与JS逻辑,实现类似音乐播放器歌词的滚动展示。文中提供完整代码示例,包含HTML布局、CSS样式及JS控制逻辑,并指出部分浏览器兼容性问题,供开发者参考实现。
JavaScript实现文字滚动效果概述
本文分享了一段使用JavaScript实现文字滚动效果的具体代码,供读者参考。
此前已介绍过多种常见的JS动画效果,本文将探讨一种相对少见但几乎人人都见过的动画形式。例如在使用酷狗音乐或网易云音乐搜索和播放歌曲时,歌词页面通常会出现歌词滚动效果。本文实现的动画与此类似,但额外增加了文字竖直排列并滚动的功能,使其更具特色。
文字垂直排列的CSS属性解析
在深入代码之前,先简要介绍实现文字垂直排列的关键CSS属性:writing-mode。
该属性的取值方式如下:
(1)标准取值包括:horizontal-tb、vertical-rl、vertical-lr、lr-tb、tb-rl。 (2)兼容写法为:-webkit-writing-mode,取值同上。 需要注意的是,lr-tb和tb-rl在IE浏览器中不兼容。
默认值为normal,适用于除table-row-group、table-column-group、table-row、table-column之外的所有元素。该属性支持继承,但不支持动画效果。计算值为特定值。
以下是对writing-mode各取值的具体解释:
(1)horizontal-tb:水平方向自上而下的书写方式。即 left-right-top-bottom(类似IE私有值lr-tb) (2)vertical-rl:垂直方向自右而左的书写方式。即 top-bottom-right-left(类似IE私有值tb-rl) (3)vertical-lr:垂直方向自左而右的书写方式。即 top-bottom-left-right (4)lr-tb:左-右,上-下。对象中的内容在水平方向上从左向右流入,后一行在前一行的下面。 所有的字形都是竖直向上的。这种布局是罗马语系使用的(IE) (5)tb-rl:上-下,右-左。对象中的内容在垂直方向上从上向下流入,自右向左。后一竖行在前一竖行的左面。全角字符是(6)竖直向上的,半角字符如拉丁字母或片假名顺时针旋转90度。这种布局是东亚语系通常使用的(IE)
文字滚动效果代码实现
HTML结构代码如下:
<body style="font-size: 12px;" >
<section class="topBox">
<div class="topBoxTxt">
<ul class="txtBox" id="txtBox">
</ul>
</div>
</section>
<script type="text/javascript" src="index.js" ></script>
<script>
(function(win){
//文字水平排列滚动
// hor();
// horizontal(0);
//文字垂直排列滚动
$(".txtBox").addClass("txtBox_4");
ver();
vertical(0);
//移动端适配
var doc = win.document;
var docEl = doc.documentElement;
var tid;
function refreshRem() {
var width = docEl.getBoundingClientRect().width
if (width > 768) {
width = 768;
}
var rem = width / 7.5;
docEl.style.fontSize = rem + 'px';
docEl.style.fontSize = rem + 'px';
docEl.style.fontSize = rem + 'px';
}
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
win.addEventListener('pageshow', function(e) {
if (e.persisted) {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}
}, false);
refreshRem();
})(window);
</script>
</body>CSS样式代码如下:
body,html{
width:100%;
height:100%;
position: relative;
background: #232226;
overflow-y: auto;
overflow-x: hidden;
}
.topBox,.topBoxTxt{
width:100%;
height:auto;
position: relative;
}
.topBoxTxt{
text-align: center;
height:auto;;
color:#fff;
font-size: 0.36rem;
padding-top:55px;
}
.txtBox{
width: 5.6rem;
height: 5.2rem;
margin:0 auto;
overflow-y: scroll;
}
.txtBox>li{
opacity: 0.5;
height:0.74rem;
}
.txtBox>li:first-child{
padding-top:60px;
}
.txtBox>li.hotColor{
opacity: 1;
}
.txtBox_4{
width:4.6rem;
height: 7.5rem;
overflow-x: auto;
white-space: nowrap;
display: block;
}
.txtBox_4>li{
writing-mode:tb-rl;
writing-mode:vertical-rl;
-webkit-writing-mode: vertical-rl;
height: 0;
line-height: 0.75rem;
word-wrap:break-word;
}
.txtBox_4>li{
width:0.4rem;
text-align: center;
margin:0 0.1rem;
display: inline-table;
position: relative;
}JavaScript逻辑代码如下:
var freq=10;//滚动频率
var fraction=9/10;// 水平文字高亮显示行在歌词显示区域中的固定位置百分比
var frac=3/10;// 垂直文字高亮显示行在歌词显示区域中的固定位置百分比
var timer=true;//定时器
var num=-1;//当前行下标
var time;//滚动距离
var eul = document.getElementById("txtBox");
var lis=[
{"offset":3000, "text":"我总是轻描淡写告诉你我的愿望"},
{"offset":6000, "text":"也给你千言万语都说不尽的目光"},
{"offset":9000, "text":"这世界总有人在忙忙碌碌寻宝藏"},
{"offset":12000, "text":"却误了浮世骄阳也错过人间万象"},
{"offset":15000, "text":"古城里长桥上"},
{"offset":18000, "text":"人如海车成行"},
{"offset":21000, "text":"你笑得像光芒"},
{"offset":24000, "text":"蓦然把我照亮"},
{"offset":27000, "text":"风轻扬夏未央"},
{"offset":30000, "text":"林荫路单车响"},
{"offset":33000, "text":"原来所谓爱情"},
{"offset":36000, "text":"是这模样"},
{"offset":39000, "text":""}
]
var count=lis.length%7+5;
//文字水平排列滚动
function hor(){
for (var i = 0; i <lis.length; i++) {
var eli = document.createElement("li");
eli.innerText = lis[i].text;
eul.appendChild(eli);
}
for(var j=0;j<count;j++){
var eli = document.createElement("li");
eli.innerText ="";
eul.appendChild(eli);
}
}
function horizontal(lineno){
common(lineno,horizontal);
var scrollTop;
var ep = eul.children[lineno];
if(30<ep.offsetTop<eul.clientHeight*fraction){
scrollTop=ep.offsetTop;
}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 = scrollTop;
}else {
var step = Math.ceil(Math.abs(eul.scrollTop - scrollTop)/(time/freq));
scrollT(eul.scrollTop, scrollTop, step);
}
}
function scrollT(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(scrollT.bind(this, crt, dst, step), freq);
};
//文字垂直排列滚动
function ver(){
console.log(eul)
for (var i = 0; i <lis.length; i++) {
var eli = document.createElement("li");
eli.innerHTML = lis[i].text;
eul.appendChild(eli);
if(eli.innerText.length<15){
eli.style.marginBottom=(15-eli.innerText.length)+"em";
}
}
for(var j=0;j<count;j++){
var eli = document.createElement("li");
eli.innerText ="";
eul.appendChild(eli);
}
}
function vertical(lineno){
common(lineno,vertical);
var scrollLeft;
var ep = eul.children[lineno];
if (ep.offsetLeft < eul.clientWidth*frac){
scrollLeft = 0;
} else if (ep.offsetLeft > (eul.scrollWidth - eul.clientWidth*(1-frac))){
scrollLeft = eul.scrollWidth - eul.clientWidth;
} else {
scrollLeft = ep.offsetLeft - eul.clientWidth*frac;
}
// 如用户拖动滚动条导致当前显示行超出显示区域范围,下一行直接定位到当前显示行
if (eul.scrollLeft > (scrollLeft + eul.clientWidth*frac)|| (eul.scrollLeft + eul.clientWidth*frac) < scrollLeft){
eul.scrollLeft = scrollLeft;
} else {
var step = Math.ceil(Math.abs(eul.scrollLeft - scrollLeft)/(time/freq));
scrollL(eul.scrollLeft, scrollLeft, step);
}
}
function scrollL(crt, dst, step){
if(Math.abs(crt - dst) < step){
return;
}
if(crt < dst){
eul.scrollLeft += step;
crt += step;
} else {
eul.scrollLeft -= step;
crt -= step;
}
setTimeout(scrollL.bind(this, crt, dst, step), freq);
}
function common(lineno,fn){
if (lineno ==0) {
time = lis[lineno].offset;
} else {
time = lis[lineno].offset - lis[lineno-1].offset;
}
timer = setTimeout(fn.bind(this, lineno+1), time);
num=lineno;
//若滚动到最后一行,则从头开始,并把每一行文字均取消高亮
if(lineno==lis.length-1){
for(var i=0;i<(eul.children).length-1;i++){
eul.children[i].setAttribute("class", "");
}
lineno=0;
timer = setTimeout(fn.bind(this, lineno), time);
}
if (lineno > 0) {
eul.children[lineno-1].setAttribute("class", "");
}
var ep = eul.children[lineno];
ep.setAttribute("class", "hotColor");
}滚动过程中可能存在一些细微瑕疵,有兴趣的读者可自行调整优化。如需运行示例,请确保引入jQuery文件。
以上就是本文的全部内容,希望对各位的学习有所帮助,也欢迎大家继续支持本站。