虚拟dom组件

35 阅读2分钟

本人已参与「新人创作礼」活动,一起开启掘金创作之路

日常开发中,我们经常遇见返回大量的数据,这个时候,如果一次性渲染会导致页面异常的卡顿,遇到这个情况,大部分人采取的应该都是分页的功能,输入获取到大量的数据,但是渲染的数据却只是一小部分,从而解决页面因渲染大量的dom而导致的卡顿

但是并不是所有情况都适合使用分页的功能,比如聊天信息,在获取聊天信息的时候,分页功能就不合适了,所有这个时候,应该采取虚拟dom的方法

虚拟dom个人认为就是渲染固定的几个dom,然后通过修改dom的内容,从而呈现出一种把全部数据渲染的假象,这样就可以减少浏览器的压力,从而不使页面卡顿

思路大致如下

首先获取到容器的高度,并且给容器添加scroll事件,

确定每一行的高度,然后判断出铺满容器需要多少个,

同时需要在容器的子元素(也就是每一行的父元素的兄弟元素)设置高度

这个高度是假象为全部数据渲染后的高度,用来撑起容器的,从而使滚动条可以滚动

代码如下

 const [dd,setDd]=React.useState<any>([])
    const [xr,setXr]=React.useState<any>([])
    const boox=React.useRef(null)
    const shuji=React.useRef({
        height:0,
        linheight:65,//每一行的高度,包括margin
        xrnumber:0,
        hcnumber:8,//以防出现空白的,多渲染
    })
    React.useEffect(()=>{
        const {offsetHeight}=boox.current!
        const {hcnumber,linheight}=shuji.current
        let xrnumber=Math.ceil(offsetHeight/linheight)+hcnumber//渲染出来的dom个数
        shuji.current={height:offsetHeight,xrnumber,hcnumber,linheight}
        const d=new Array(1000).fill(1).map((item,index)=> index + 1 )
        let boxw:any=document.querySelector('.boox_w')
        boxw.style.height=d.length*linheight+'px'//撑起容器的dom高度
        setXr(d.slice(0,xrnumber))
        setDd(d)
    },[])
  return (
    <div className='boox' ref={boox} >
        <div className='boox_q' style={{height:shuji.current.height}} onScroll={(e)=>{
            let dom:any=e.target 
            let d:any=document.querySelector('.boox_e')
            let sco=dom.scrollTop-(dom.scrollTop%65)//注意这里是使用%,每一次偏差都不会超过65
            d.style.transform = `translate3d(0, ${sco}px, 0)`//假象,看起来像滚动
            setXr(dd.slice(Math.floor(dom.scrollTop/65),Math.floor(dom.scrollTop/65)+shuji.current.xrnumber))
        }}>
            <div className='boox_w'></div>
            <div className='boox_e'>
                {xr.map((T:any,I:any)=><div className='boox_r' key={I}>{T}</div>)}
            </div>
        </div>
    </div>
  )

css如下

.boox{
    position: relative;
    left:0;
    top:60px;
    // overflow: hidden;
    bottom:0;
    right: 0;
    width: 500px;
    height: 500px;
    .boox_q{
        overflow-y: scroll;
        position: absolute;
        width: 100%;
        .boox_w{
            position: absolute;
            left:0;
            top:0;
            right: 0;
        }
        .boox_e{
            .boox_r{
                width: 100%;
                height: 60px;
                margin-top: 5px !important;
                border-radius: 5px;
                background-color: red;
                color: white;
                font-size: 20px;
            }
        }
    }
}

修改图如下

image.png

image.png