精准滚动到指定行的实现
本帖最后由 马黑黑 于 2025-3-21 18:28 编辑 <br /><br /><style>.mama {display: flex;flex-direction: column;padding: 0 10px;background: #eee;width: 600px;height: 90px;overflow: auto;outline: thick double gray;border-radius: 3px;margin: 20px auto;position: relative;}
.para {margin: 0;padding: 0;line-height: 30px;max-height: 30px;flex: auto;font-size: 16px;}
.red { color: red; font-size: 20px; }
.tMid { text-align: center; }
#num { width: 40px; }
</style>
<div class="mama"></div>
<p class="tMid">
<button id="btnOk">滚动到</button>
<input id="num" type="text" value="2" onkeyup="this.value=this.value.replace(/[^0-9]/g,'')" />
</p>
<p>上面的演示,通过按钮驱动的滚动不会出现顶行、底行文本被切断现象,但通过滚动条滚动文本时这种情况可能会发生。按钮滚动是精准滚动,实现核心在于:容器元素使用flex弹性布局,纵向内边距设为0、设置好高度,同时position必须设置(绝对或相对定位都行);子元素一般使用p标签,内、外边距都设为0、限制最大高度和行高一致(行高也可以在容器元素设置),注意字体大小不能高于行高。在此基础上就可以通过JS的计算精准滚动到指定行。下面给出关键代码:</p>
<div id="hEdiv" data-name="核心代码"><pre id="hEpre">
/* 容器核心CSS代码 */
display: flex;
flex-direction: column;
padding: 0 10px;
background: #eee;
width: 600px;
height: 90px;
position: relative;
/* 子项(p标签)核心代码 */
margin: 0;
padding: 0;
line-height: 30px;
max-height: 30px;
flex: auto;
font-size: 16px;
<!-- html结构代码 -->
<div class="mama">
<p>第一行</p>
<p>第一行</p>
<p>…………</p>
<p>第N行</p>
</div>
// JS依据指定行计算容器翻滚(scrollTo)位置
p元素.offsetTop - (Math.ceil(显示行数 / 2) * 行高) + 行高
</pre></div>
<script type="module">
const mama = document.querySelector('.mama');
const lineHeight = 30;
const showLines = 5;
let last;
let ps = [];
const generatePs = (lines) => {
Array.from({length: lines}).forEach((s,k) => {
const p = document.createElement('p');
k === last ? p.classList.add('para', 'red') : p.classList.add('para');
p.innerText = `${k+1}. ${Math.random().toString(36).substring(2, Math.round(Math.random() * 20) + 10)}`;
mama.appendChild(p);
ps.push(p);
});
};
const scrolling = () => {
const idx = num.value - 1;
const scrollPos = ps.offsetTop - (Math.ceil(showLines / 2) * lineHeight) + lineHeight;
mama.scrollTo({left: 0, top: scrollPos , behavior: 'smooth'});
if (last >= 0) ps.classList.remove('red');
ps.classList.add('red');
last = idx;
};
num.oninput = () => {
if (num.value > ps.length) num.value = ps.length;
if (num.value <= 0) num.value = 1;
};
mama.style.setProperty('height', showLines * lineHeight + 'px');
generatePs(100);
btnOk.onclick = () => scrolling();
scrolling();
import hlight from 'https://638183.freep.cn/638183/web/helight/helight1.js';
hlight.hl(hEdiv, hEpre);
</script>
JS计算滚动到的位置依据为指定行,若指定行原始位置在容器元素纵向一半的上方,或若翻滚到最后一页时它们最高位置只能在容器元素纵向方向的一半以下,则它们在原始位置高亮,因为容器元素的翻滚动作是有限制的。 创造出公式实现精准滚动,感觉相当伟大,思路胜过一切{:4_199:} 在想这么复杂的运算,代码肯定不止这么一丢丢,
果然有大量的JS代码,还有封起来的部分{:4_199:}
花飞飞 发表于 2025-3-21 18:38
在想这么复杂的运算,代码肯定不止这么一丢丢,
果然有大量的JS代码,还有封起来的部分
封装起来的部分是代码高亮用的模块。实现滚动的代码实际上并不多,代码中有生成100个p标签的部分 花飞飞 发表于 2025-3-21 18:33
创造出公式实现精准滚动,感觉相当伟大,思路胜过一切
这个不算太复杂,主要是要配合CSS 马黑黑 发表于 2025-3-21 18:25
JS计算滚动到的位置依据为指定行,若指定行原始位置在容器元素纵向一半的上方,或若翻滚到最后一页时它们最 ...
这个是不是为多行歌词做铺垫的,老师当之无愧! 亚伦影音工作室 发表于 2025-3-21 19:04
这个是不是为多行歌词做铺垫的,老师当之无愧!
是的,下一个升级版模块用上这个做法 马黑黑 发表于 2025-3-21 19:03
这个不算太复杂,主要是要配合CSS
会算的不算复杂。。。{:4_173:}我觉得就是超级英雄。。 马黑黑 发表于 2025-3-21 19:02
封装起来的部分是代码高亮用的模块。实现滚动的代码实际上并不多,代码中有生成100个p标签的部分
看到那100行了。{:4_173:}有耐心敲那么多不一样的行 花飞飞 发表于 2025-3-21 19:14
看到那100行了。有耐心敲那么多不一样的行
可以间隔敲数字。超过100行会变成100行 花飞飞 发表于 2025-3-21 19:14
会算的不算复杂。。。我觉得就是超级英雄。。
这和数钱钱是一个道理,都会算 马黑黑 发表于 2025-3-21 19:15
可以间隔敲数字。超过100行会变成100行
{:4_173:}你一般敲代码的时候配的什么音乐。。 马黑黑 发表于 2025-3-21 19:16
这和数钱钱是一个道理,都会算
完全不一回事
钱钱看了两眼 放 光。。。
这个公式么,给我套用都勉强,别说创造了{:4_170:} 这个设计很细致,考虑周全,所以能精准到位,很赞{:4_199:} 红影 发表于 2025-3-21 19:56
这个设计很细致,考虑周全,所以能精准到位,很赞
但是滚动条的滚动不好控制。这是一个高发频率的滚动操作,需要引入防抖和节流,又得估计常规翻页的幅度,难度较大,好在我们不需要处理它 花飞飞 发表于 2025-3-21 19:27
完全不一回事
钱钱看了两眼 放 光。。。
这个公式么,给我套用都勉强,别说创造了
你两眼放光着看看就像看钱钱一样就成了 花飞飞 发表于 2025-3-21 19:26
你一般敲代码的时候配的什么音乐。。
一般都是轻音乐 马黑黑 发表于 2025-3-21 20:08
但是滚动条的滚动不好控制。这是一个高发频率的滚动操作,需要引入防抖和节流,又得估计常规翻页的幅度, ...
这里面涉及的内容还真挺多的呢{:4_187:} 红影 发表于 2025-3-21 21:44
这里面涉及的内容还真挺多的呢
办公软件的翻页时不存在这类问题吧,印象中