原生js实现模拟滚动条

JavaScript 实现虚拟滚动技术 虚拟滚动(有时称为 虚拟列表、虚拟滚动条)是 JavaScript 中的一种技术,旨在,尤其是当有成千上万的数据项时,直接渲染整个列表会导致性能问题。虚拟列表通过只渲染用户视口中可见的那一部分列表项,从而减少 DOM 元素的数量和内存占用,提高渲染性能。 阅读详情

最近在准备面试看到这个面试题,感觉貌似不少公司都会问一下相关问题,所以在这简单实现一下

页面如下

 .parent {
        width: 300px;
        height: 200px;
        margin: 0 auto;
        background: rgba(0,0,0,.4);
        overflow:hidden;
        position:relative;
        border:1px solid #000;
        -webkit-user-select:none; 
       -moz-user-select:none; 
       -ms-user-select:none; user-select:none;
    }
    input {
        display: block;
        margin: 0 auto;
    }
    #content {
        width:300px;
        min-height: 200px;
        line-height: 30px;
        position:absolute;
        top:0;left:0;
    }
    #barbox{
        width:20px;
        position:absolute;
        right:0;
        height:100%;
        top:0;
        background-color: #fff;
        opacity: 0;
    }
    #bar{
        width:100%;
        position: absolute;
        top:0;
        height:20px;
        background-color: pink;
    }
</style>
<body>
    <div id="parent" class="parent">
        <div id="content" class="content">
            <ul>
                <li>1</li>
                <li>2</li>
                <li>3</li>
                <li>4</li>
                <li>5</li>
                <li>6</li>
                <li>7</li>
                <li>8</li>
                <li>9</li>
                <li>10</li>
            </ul>
        </div>
        <div id="barbox" class="barbox">
            <div  id="bar" class="bar"></div>
        </div>
    </div>
</body>

大概说一下思路在这里插入图片描述

  1. 首先分为四个部分:最外层容器parentDom ,内容盒子contentDom ,bar的容器盒子barboxtDom 和bar按钮
  2. 滑块的高度/bar的容器盒子的高度 = 可视容器(最外层容器)高度/内容盒子的高度,首先前三者可知,从而可以得出bar的高度
  3. 滑块可移动范围为器容器内,具体范围是 top为 0 到 bar的容器盒子的高度 - bar的高度
  4. bar下移则内容向上移动展示,所以 bar与内容盒子两者定位top相反
  5. 鼠标移出barboxtDom 与 鼠标松开时不记录鼠标移动轨迹

然后根据以上逻辑得出一下代码

js代码

var barObj = {
            parentDom : document.getElementById('parent'),
            contentDom : document.getElementById('content'),
            barboxtDom : document.getElementById('barbox'),
            barDom : document.getElementById('bar'),
            parentH : null,
            contentH : null,
            barboxtH : null,
            contentScrollH:null,
            barPositionY:0,//滑块当前位置
            barLimits:null,//滑块最大定位
            contentLimits:null,//内容最大定位
            mouseStartTop:null,//鼠标开始的位置
            mouseScrollH:null,//鼠标移动的距离(Y)
            init:function(){
                this.parentH = this.parentDom.clientHeight;
                this.contentH = this.contentDom.clientHeight;
                this.barboxtH = this.barboxtDom.clientHeight;
                //得到bar的高度
                let barH = this.parentH/this.contentH*this.barboxtH;
                //bar的top最大值
                this.barLimits = this.barboxtH - barH;
                //内容的top最大值的绝对值
                this.contentLimits = this.contentH - this.parentH;
                this.barDom.style.height = barH+'px'; 
                if (document.addEventListener) { 
                    this.barDom.addEventListener('mousedown', this.start);
                    this.parentDom.addEventListener('mouseover', this.moveover);
                    this.parentDom.addEventListener('mouseout', this.moveout);
                }
            },
            start:function(event){//鼠标按下时开始监听鼠标移动事件
                barObj.mouseStartTop = event.clientY
                barObj.barDom.addEventListener('mousemove', barObj.move);
                barObj.barDom.addEventListener('mouseup', barObj.stop);
                barObj.barDom.addEventListener('mouseout', barObj.stop);
            },
            move:function(event){//鼠标移动时的逻辑
                barObj.mouseScrollH = event.clientY - barObj.mouseStartTop;
                console.log(barObj.mouseScrollH)
                let contentPositionY = 0;
                if((barObj.mouseScrollH + barObj.barPositionY)<0){
                    barObj.barPositionY = 0
                    barObj.barDom.style.top = '0px';
                    barObj.contentDom.style.top = '0px';
                }else if((barObj.mouseScrollH + barObj.barPositionY)>barObj.barLimits){
                    barObj.barPositionY = barObj.barLimits
                    barObj.barDom.style.top = barObj.barLimits+'px';
                    barObj.contentDom.style.top = -barObj.contentLimits+'px';
                }else{
                    contentPositionY = (barObj.mouseScrollH + barObj.barPositionY)/barObj.barLimits  * barObj.contentLimits;
                    barObj.barDom.style.top = (barObj.mouseScrollH + barObj.barPositionY)+'px';
                    barObj.contentDom.style.top = -contentPositionY+'px';
                }

            },
            stop:function(envet){//鼠标移出barboxtDom 与 鼠标松开时解除鼠标移动的监听
                barObj.barPositionY = barObj.mouseScrollH + barObj.barPositionY;
                barObj.barDom.removeEventListener('mousemove', barObj.move);
                barObj.barDom.removeEventListener('mouseup', barObj.stop);
                barObj.barDom.removeEventListener('mouseout', barObj.stop);
            },
            moveover:function(){
                barObj.barboxtDom.style.opacity = '.7';
                document.onmousewheel = barObj.scrollFunc;
            },
            moveout:function(){
                barObj.barboxtDom.style.opacity = '0';
                document.onmousewheel = null;
            },
            scrollFunc : function (e) { //滚动滑轮时运行的方法
                console.log(e.deltaY)
                if(e.deltaY>0){//e.deltaY下滑为正,上滑为负
                    barObj.barPositionY+=2;
                }else{
                    barObj.barPositionY-=2;
                }
                if(barObj.barPositionY<0){
                    barObj.barDom.style.top = '0px';
                    barObj.contentDom.style.top = '0px';
                    barObj.barPositionY = 0;
                }else if(barObj.barPositionY>barObj.barLimits){
                    barObj.barDom.style.top = barObj.barLimits+'px';
                    barObj.contentDom.style.top = -barObj.contentLimits+'px';
                    barObj.barPositionY = barObj.barLimits;
                }else{
                    contentPositionY = barObj.barPositionY/barObj.barLimits  * barObj.contentLimits;
                    barObj.barDom.style.top = barObj.barPositionY +'px';
                    barObj.contentDom.style.top = -contentPositionY+'px';
                }

            },
            topF:function(){
                barObj.barDom.style.top = '0px';
                barObj.contentDom.style.top = '0px';
                barObj.barPositionY = 0;
            }
        }
        barObj.init()
JavaScript实现非等高元素的虚拟滚动加载 当一个元素进入可见区域时,我们将加载该元素的内容,当一个元素离开可见区域时,我们将卸载该元素,以保持页面上只有可见区域内的元素。我们将使用Intersection Observer API来检测元素是否可见,并根据可见区域内的元素动态加载和卸载元素。虚拟滚动加载是一种优化长列表渲染性能的技术,它可以在页面上只渲染可见区域内的元素,而不是一次性渲染所有的元素。通过这种方式,我们实现了非等高元素的虚拟滚动加载效果。只有可见区域内的元素才会被加载和渲染,其他元素将被动态地卸载和重新加载,以提高性能和内存占用。 阅读详情

相关推荐

原生JavaScript实现跨浏览器自定义滚动条

在现代网页设计中,滚动条虽小,却承担着至关重要的交互角色。它不仅决定了用户如何浏览内容,也直接影响着页面整体的视觉风格与交互体验。传统浏览器提供的默认滚动条样式受限于系统与浏览器本身,风格单一且难以统一,尤其在跨平台展示时容易破坏页面设计的一致性。因此,使用原生JavaScript实现高度可定制、兼容性强的自定义滚动条,已成为前端开发中不可或缺的一项技能。本章将从滚动条的基本功能入手,逐步剖析其样式控制的局限性,并引出为何需要自定义滚动条的核心原因。

weixin_35706255的博客 457

JavaScript实现虚拟滚动

1.创建一个容器元素,用来显示列表内容。2.绑定滚动事件,当滚动条滚动时,触发加载列表项的函数。在这种方式中,只有当前可见范围内的列表项会被生成和加载,减少了渲染和内存消耗。需要注意的是,这只是一种基本的实现方式,具体的实现可能会因为需求的不同而有所变化,例如可以添加缓存、虚拟化窗口等优化。

weixin_53376443的博客 2553

告别混乱!AutoSar BswM模式管理实战:手把手教你配置Rule与ActionList(附避坑指南)

本文详细解析了AutoSar BswM模式管理的实战配置,重点介绍了Rule与ActionList的高效组合方法,帮助开发者避免常见陷阱。通过具体案例演示了从基础到复杂的配置步骤,包括模式仲裁、逻辑表达式构建及ActionList优化策略,提升汽车电子系统的协调性与可靠性。

weixin_27066963的博客 259

CSS3过渡效果小练习-进度条

Document

nuomi_w的博客 1641

Unidbg逆向阿里系App签名:从环境补全到算法还原实战

在移动安全与协议分析领域,理解应用层签名机制是核心挑战之一。签名算法作为保障通信安全与身份验证的关键技术,其原理通常涉及哈希、加密及密钥协商等基础密码学概念。在Android平台,核心签名逻辑常被加固并隐藏于Native层SO库中,以对抗动态调试与静态分析,这为安全研究和协议兼容带来了技术障碍。Unidbg作为一种基于模拟执行的逆向工程工具,通过模拟ARM指令集和系统调用,允许研究者在脱离真机环境的情况下,可控地执行和调试SO文件,为解决此类问题提供了创新思路。其技术价值在于实现了对加固代码的确定性分析与算

weixin_42525738的博客 939

hi3516cv610在PQStream上实现拉出图像,windows和板端操作记录

PQStream拉出图像

weixin_51838255的博客 728

记录--虚拟滚动探索与封装

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1. 介绍 什么是虚拟滚动?虚拟滚动就是通过js控制大列表中的dom创建与销毁,只创建可视区域dom,非可视区域的dom不创建。这样在渲染大列表中的数据时,只创建少数的dom,提高性能。 2. 分类 在虚拟滚动技术中,虚拟滚动可以分为定高虚拟滚动和非定高虚拟滚动。定高指的是每一个列表元素都是高度固定的,非定高指的是每一个列表元素...

林恒的博客 581

FLUKA软件在Ubuntu的安装指南(亲测有效)

FLUKA其强大的蒙特卡洛模拟能力使得用户能够模拟复杂的辐射相互作用过程

chencheng1127的博客 2886

原生js监听滚动条_原生js实现模拟滚动条

当页面中有很多滚动条,它们相互嵌套,很不好看,这时就会模拟滚动条,并给这个滚动条好看的样式,使得页面美观。模拟滚动条很多时候是去用jquery插件,然后写几行代码就搞定了。不过随着mvvm的快速发展,很多时候都懒得用jquery了,这就是本文的动机,本屌力求用简单的不依赖jquery只依赖mvvm(avalon) api的代码,完成一个简易的滚动条。要求:1.鼠标滚轮可以让滚动条工作,界面滚动2....

weixin_29271263的博客 390

STM32F103ZE精英板驱动ESP8266与DHT11构建物联网网关,实现乐联网温湿度数据实时监控

本文详细介绍了如何使用STM32F103ZE精英板驱动ESP8266与DHT11构建物联网网关,实现乐联网温湿度数据实时监控。从硬件选型、连接调试到乐联网平台配置和STM32程序开发,提供了完整的实现步骤和常见问题解决方案,适合物联网入门开发者参考。

weixin_30823001的博客 78

Simulink实战:火电机组一次调频与AGC协同控制建模与仿真解析

本文详细解析了如何使用Simulink进行火电机组一次调频与AGC协调控制的建模与仿真。通过系统架构设计、参数设置和模块实现,阐述了如何实现两者的协同控制,确保电网频率稳定。文章提供了实用的建模技巧、参数整定经验和性能评估方法,为电力系统仿真工程师提供了有价值的实践指导。

c7d8e9的博客 308

关于模拟一个滚动条的实现------横向滚动条 原生 html css js

但是 overflow: auto;的滚动条太难看了,尽管可以重些一些样式,但是移动端仍不支持。无奈只能做出妥协,遂想 可否实现自定义模拟一个滚动指示器出来,以求满足业务要求。在日常开发中会遇到一些时候,在实现内部滚动的同时,也希望用户看到当前的滚动位置。

qq_46634851的博客 1117

嵌入式工程师成长之路(1)——元件基础(完整版)

为什么你的电路总是“玄学”故障?答案藏在这些元件里! 0欧电阻竟能引发信号反射?5V转3.3V电平匹配失败导致MCU烧毁?电容降压设计让电源“滋滋”响?——这些坑,本文全填平! 优快云硬件领域头部博主十年踩坑经验汇总,覆盖电阻、电容、电感核心难点+高频实战问题,让你从“调试地狱”直通“一次成功”!

云轩阁 2万+

原生js实现模拟滚动条加完整注释,包你看得懂

实现效果: 代码加注释如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta ...

qq_41988554的博客 284

C#怼倍福TwinCAT3:ADS协议封装实战(附完整读写源码+避坑清单)

变量名大小写敏感:PLC里定义的是GVL.bStart,你写GVL.BStart绝对读不到;数组访问格式:PLC数组是,C#里读单个元素要写,读整个数组不用写索引;句柄要释放:用创建的句柄,一定要用using包起来,否则会占着资源;PLC必须运行:哪怕变量定义对了,PLC没Run(只是Login)也读不到数据;路由配置:如果上位机和PLC不在一个网段,要在TwinCAT3里添加路由(Router→Edit Routes)。倍福ADS通信其实不难,核心就是“配置对+变量名写对+数据类型匹配”。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 950

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

vue3虚拟滚动条(非虚拟列表)

vue3 虚拟滚动条或者叫做 模拟滚动条

鱼猫的博客 642

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

原生js、html、css实现自定义select框(带搜索框和滚动条)

原生js、html、css实现自定义select框(带搜索框和滚动条)

Blank 5896

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

模拟滚动条控制内容的滚动

模拟滚动条控制内容的滚动 #div1{ width:30px; height:500px; background:black; position: absolute; left:10px; top:10px; } #div2{ width:30px; height:30px; background:red; positio

那女孩真拽的博客 734

css改变滚动条样式兼容火狐_JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome...

今天为大家分享一下我自己制作的浏览器滚动条,我们知道用css来自定义滚动条也是挺好的方式,css虽然能够改变chrome浏览器的滚动条样式可以自定义,css也能够改变IE浏览器滚动条的颜色。但是css只能是改变IE浏览器的颜色,而且CSS不能做到改变火狐浏览器的样式和颜色。所以只能是通过JavaScript来实现了。也有插件可以做到。我分享一下我自己使用原生JavaScript实现的思路。先上个图...

weixin_35097945的博客 546

原生JS JavaScript 文本域滚动到底部 实现文本动态加载效果

文本域内容流式增加时通过定位到滚动条底部添加动态加载效果 <!DOCTYPE html> <html lang="cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale

qq_37666892的博客 452

JavaScript自定义浏览器滚动条兼容IE、 火狐和chrome

今天为大家分享一下我自己制作的浏览器滚动条,我们知道用css来自定义滚动条也是挺好的方式,css虽然能够改变chrome浏览器的滚动条样式可以自定义,css也能够改变IE浏览器滚动条的颜色。另外,滚动条的总高度就是可视区域的高度,滑块的高度=可视区域的高度/内容的总高度*可视区域的高度。以上就是我自己实现的整个过程,其中也存在不少BUG,比如没有解决浏览器缩放时候的问题。先定义滑块和滑动条,然后在定义一个装内容的盒子,布局很简单,body的 overflow设置成hidden隐藏默认滚动条。

lmrylll的博客 433

textarea高度随内容自动改变

需求 textarea默认的高度不是对着内容变化,而是随着内容增多,出现了滚动条。目前的需求是实现一个能够输入的textarea,并且高度跟着内容变化。 发现了一个比较好用的插件flexText,但是这个基于jquery写的,目前的技术栈是react,所以简单看了下,然后用原生的js模拟了一个实现。 原理: html结构: div class="body"> di

遇见更好的自己 2万+

textarea随文字的增多自动增高或者自动减少

谷歌、IE、Opera默认显示两行文本,火狐默认显示3行文本,行数超过两行是会出现滚动条,可以自己设定设定一些行数来进行强制多少行进行显示。 方法一:div模拟textarea文本域轻松实现高度自适应(缺点就是没有了placeholder提示语) 因为textarea不支持自适应高度,就是定好高度或者是行数之后,超出部分就会显示滚动条,看起来不美观。 而用DIV来模拟时,首先遇到的问题是:div怎...

qq_45375420的博客 4208

PHP表单自适应,如何让textarea实现高度自适应和用div模拟textarea表单的方法

我想写个评论框,开始是用textarea写的,但是有个问题就是文本写的多了,就会出现滚动条,这样何不美观。于是,我就想在点击评论,默认显示一行,当输入的文字超过一行或者输入Enter时,输入框的高度会随着改变,直到输入完毕。下面分享2种实现textarea高度自适应的做法:第一种:是用div来模拟textarea来实现的,用CSS控制样式,不用JS;第一种:是利用JS控制的(因为存在浏览器兼容问题...

weixin_32445049的博客 264

php怎么设置文本框的高度,如何让textarea实现高度自适应和用div模拟textarea表单的方法...

我想写个评论框,开始是用textarea写的,但是有个问题就是文本写的多了,就会出现滚动条,这样何不美观。于是,我就想在点击评论,默认显示一行,当输入的文字超过一行或者输入Enter时,输入框的高度会随着改变,直到输入完毕。下面分享2种实现textarea高度自适应的做法:第一种:是用div来模拟textarea来实现的,用CSS控制样式,不用JS;第一种:是利用JS控制的(因为存在浏览器兼容问题...

weixin_39900676的博客 269

textarea如何实现高度自适应?

今天需要些一个回复评论的页面,设计师给的初始界面就是一个只有一行的框。然后当时就想这个交互该怎么实现比较好,然后想起了新浪微博的做法:点击评论,默认显示一行,当输入的文字超过一行或者输入Enter时,输入框的高度会随着改变,直到输入完毕。顿时觉得这个细节做得挺不错的,可以效仿下。下面分享2种实现textarea高度自适应的做法,一种是用div来模拟textarea来实现的,用CSS控制样式,不用...

xinjiatao的专栏 250
上一篇: window.open打开新窗口被浏览器拦截的处理方法
WebSunshine
博客等级 码龄9年 22粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值