不知道你们有没有遇到过这样的需求,在某个dom
元素中添加新的子元素,而后要求若是新添加的新元素超出容器的范围,那么咱们须要自动滚动到新添加的子元素的位置,以下图所示效果:javascript
那么接下来咱们一边学习一些dom
元素滚动相关的知识点,一边实现一个上图的效果和一些其余滚动相关的功能。css
scrollTop
属性是一个描述容器元素内容的top值与容器元素(viewport
)视口顶部top
值之间的差值,即容器中内容向上滑动后超出容器视口的部分。能够经过修改此属性控制滚动状态。html
clientHeight
是描述容器高度的dom
属性。java
scrollHeight
是描述容器内容高度的dom
属性。闭包
三个属性的关系以下图所示:dom
此方法用来获取元素布局所需的一些几何属性,好比left
、right
、top
、bottom
、height
、width
等。函数
dom
容器的scrollTo
方法能够用来直接控制滚动条滚动指定的距离。当须要滚动到指定元素时,使用此方法比较方便。布局
dom
容器的scrollTo
方法能够用来直接控制滚动条滚动到指定位置。在控制滚动条滚动到顶部或者底部的时候使用此方法比较方便。学习
咱们先准备一个html
flex
<!DOCTYPE html>
<html>
<head>
<title>滚动条设置详解</title>
<style> #scroll_container{ height: 500px; width: 500px; overflow-y: scroll; padding: 50px; box-sizing: border-box; } .scroll_item{ height: 200px; width: 500px; margin-top: 20px; background-color: aquamarine; display: flex; align-items: center; justify-content: center; } </style>
</head>
<body>
<div id="scroll_container">
<div id="scroll_container">
<div id="item1" class="scroll_item">
<span>1</span>
</div>
<div id="item2" class="scroll_item">
<span>2</span>
</div>
<div id="item3" class="scroll_item">
<span>3</span>
</div>
<div id="item4" class="scroll_item">
<span>4</span>
</div>
<div id="item5" class="scroll_item">
<span>5</span>
</div>
</div>
<button onclick="addItem()">添加一个元素</button>
</div>
</body>
<script> let container=document.getElementById("scroll_container"); let index=5; //添加一个元素 function addItem(){ index+=1; let item=`<div id="${'item'+index}" class="scroll_item"> <span>${index}</span> </div>`; container.innerHTML+=item; setTimeout(()=>{ scrollToIndex(); }) } </script>
</html>
复制代码
上面的代码包含一个可滚动的区域,并能够为滚动区域添加元素,也能够滚动到指定的元素位置,大体效果以下图。
以前已经说明过scrollTop
的含义,咱们能够经过修改容器元素scrollTop
值来控制滚动条滚动。scrollTop
的值越大,滚动条相对于原始状态(scrollTop
为0时)的滚动距离越大。
了解了scrollTop
的含义,咱们就能够利用scrollTop
来实现滚动条的控制,那么咱们先实现一个滚动到底部的实现,为上面的代码添加一个scrollToBottom()
的方法:
function scrollToBottom(){
let y=container.scrollHeight-container.clientHeight;
container.scrollTop=y;
}
复制代码
对应的若是想要实现滚动到顶部咱们只须要设置scrollTop
为0便可:
function scrollToTop(){
container.scrollTop=0;
}
复制代码
结合getBoundingClientRect()
方法咱们也能够轻松实现滚动到指定元素,其中getBoundingClientRect().top
表示子元素顶部距离父元素视口顶部的距离:
function scrollToElement(el){
container.scrollTop+=el.getBoundingClientRect().top;
}
复制代码
setInterval()
实现一下。分析一下实现动画效果的过程,动画的实现无外乎是把一个变量的变化在必定的时间内完成,所以咱们首先须要知道两个变量,变量(scrollTop
)偏移量和变化所需时间,而偏移量就是scrollTop
的最终值减去原始值,变化时长通常设置成能够修改的参数。了解了以上过程,咱们先以滚动到底部为例://首先编写一个scrollToBottom函数
function scrollToBottom(el){
if(!el){
el=container;
}
//原始值
let startTop=el.scrollTop;
//最终值
let endTop=el.scrollHeight-el.clientHeight;
//生成一个动画控制函数
let scrollAnimationFn=doAnimation(startTop,endTop,300,el);
//执行动画,每10ms执行一次
let interval=setInterval(()=>{
scrollAnimationFn(interval)
},10)
}
/** * @description: 一个生成动画控制函数的工厂函数(使用闭包) * @param { startValue:变量原始值 endValue:变量最终值 duration:动画时长 el:执行滚动动画的元素 } * @return: null */
function doAnimation(startValue,endValue,duration,el){
//使用闭包保存变量dy和step(每次动画滚动的距离)
let dy=0;
let step=(endValue-startValue)/(duration/10);
//返回动画控制函数
return function(interval){
dy+=step;
if(dy>=endValue-startValue){
clearInterval(interval);
}
el.scrollTop+=step;
}
}
复制代码
修改addItem函数添加滚动到底部动画:
function addItem(){
index+=1;
let item=`<div id="${'item'+index}" class="scroll_item"> <span>${index}</span> </div>`;
container.innerHTML+=item;
setTimeout(()=>{
// scrollToIndex();
scrollToBottom(container);
})
}
复制代码
而后为html加入一个滚动到底部的按钮:
<button onclick="scrollToBottom()">滚动到底部</button>
复制代码
//编写一个scrollToTop函数
function scrollToTop(el){
if(!el){
el=container;
}
//原始值
let startTop=el.scrollTop;
//最终值
let endTop=0;
//生成一个动画控制函数
let scrollAnimationFn=doAnimation(startTop,endTop,300,el);
//执行动画,每10ms执行一次
let interval=setInterval(()=>{
scrollAnimationFn(interval)
},10)
}
复制代码
为了适配滚动到底部咱们须要修改一下动画中止的时机判断,修改后的doAnimation()
函数以下:
function doAnimation(startValue,endValue,duration,el){
//使用闭包保存变量dy和step(每次动画滚动的距离)
let dy=0;
let step=(endValue-startValue)/(duration/10);
return function(interval){
dy+=step;
//这里改为使用绝对值判断
if(Math.abs(dy)>=Math.abs(endValue-startValue)){
clearInterval(interval);
}
el.scrollTop+=step;
}
}
复制代码
最后咱们再给html
添加一个滚动到底部按钮:
<button onclick="scrollToTop()">滚动到顶部</button>
复制代码
实现效果以下图:
<input type="number" placeholder="请输入要滚动到的元素index" style="width: 200px;"/>
<button onclick="scrollToElement()">滚动到指定元素</button>
复制代码
添加一个滚动指定元素的动画执行函数:
function scrollToElement(containerEl,el){
if(!containerEl){
//父元素
containerEl=container;
}
if(!el){
//获取到要滚动到的元素
let input=document.getElementsByTagName('input')[0];
let id='item'+input.value;
if(!input.value){
id='item'+index;
}
el=document.getElementById(id);
}
let startTop=containerEl.scrollTop;
let endTop=startTop+el.getBoundingClientRect().top;
let scrollAnimationFn=doAnimation(startTop,endTop,300,containerEl);
let interval=setInterval(()=>{
scrollAnimationFn(interval)
},10)
}
复制代码
实现效果以下:
scrollTo(x,y)
的使用方法与scrollTop
属性的使用方法基本一致,父元素的scrollTo()
方法能够控制滚动条滚动到指定位置,实际上至关于设置scrollTop
的值。举个例子说明一下:
//这里以y轴滚动为例
element.scrollTo(0,y);
element.scrollTop=y;
//上面两句的效果相同。
复制代码
因此,使用scrollTo()
方法控制滚动条与使用scrollTop基本一致,咱们只须要简单修改doAnimation()
函数,代码以下:
function doAnimation(startValue,endValue,duration,el){
//使用闭包保存变量dy和step(每次动画滚动的距离)
let dy=0;
let step=(endValue-startValue)/(duration/10);
return function(interval){
dy+=step;
if(Math.abs(dy)>=Math.abs(endValue-startValue)){
clearInterval(interval);
}
//el.scrollTop+=step;//这行代码修改成以下
el.scrollTo(0,el.scrollTop+step);
}
}
复制代码
执行效果与使用scrollTop
实现一致。
咱们一样可使用scrollBy(x,y)
实现对滚动条的控制,上面已经说明过,scrollBy()
方法是控制滚动条滚动指定距离(注意不是位置)。使用scrollBy()能够很方便的实现滚动到指定元素的需求,代码以下:
function scrollToElement(containerEl,el){
//由于getBoundingClientRect().top即为子元素顶部距离父元素顶部的距离,因此这个值就是子元素相对于父元素的偏移量,咱们传入这个值到scrollBy中,即滚动到指定元素
containerEl.scrollBy(0,el.getBoundingClientRect().top);
}
复制代码
滚动到底部:
function scrollToBottom(containerEl){
let dy=containerEl.scrollHeight-containerEl.clientHeight;
containerEl.scrollBy(0,dy);
}
复制代码
滚动到顶部
function scrollToTop(containerEl){
let dy=-(containerEl.scrollHeight-containerEl.clientHeight);
containerEl.scrollBy(0,dy);
}
复制代码
这里咱们修改一下动画生成的函数,由于这里咱们scrollBy()
的参数就是变量的偏移量,因此作出以下修改:
function scrollToBottom(containerEl){
if(!containerEl){
containerEl=container;
}
//dy即为偏移量
let dy=containerEl.scrollHeight-containerEl.clientHeight;
let scrollAnimationFn=doAnimation(dy,300,containerEl);
let interval=setInterval(()=>{
scrollAnimationFn(interval)
},10)
}
function scrollToTop(containerEl){
if(!containerEl){
containerEl=container;
}
//dy即为偏移量
let dy=-(containerEl.scrollHeight-containerEl.clientHeight);
let scrollAnimationFn=doAnimation(dy,300,containerEl);
let interval=setInterval(()=>{
scrollAnimationFn(interval)
},10)
}
function scrollToElement(containerEl,el){
if(!containerEl){
containerEl=container;
}
if(!el){
let input=document.getElementsByTagName('input')[0];
let id='item'+input.value;
if(!input.value){
id='item'+index;
}
el=document.getElementById(id);
}
//dy即为偏移量
let dy=el.getBoundingClientRect().top;
let scrollAnimationFn=doAnimation(dy,300,containerEl);
let interval=setInterval(()=>{
scrollAnimationFn(interval)
},10)
}
/** * @description: * @param {type} * @return: */
function doAnimation(dy,duration,el){
//使用闭包保存变量exe_dy和step等变量(每次动画滚动的距离)
let exe_dy=0;//已经执行的偏移量
let step=dy/(duration/10);
return function(interval){
exe_dy+=step;
if(Math.abs(exe_dy)>=Math.abs(dy)){
clearInterval(interval);
}
el.scrollBy(0,step);
}
}
复制代码
执行效果与使用scrollTop
实现一致。
以上👆就是本身对dom滚动条控制的详细总结和讲解,以及一些基本使用方法。若是错误还请指正。