elementUI中的elTable实现原理分析
2021-04-07 18:24

elementUI中的elTable实现原理图

image.png

上图是我们使用element table组件的一个常见场景,顶部固定,左侧列固定,右侧列固定,甚至底部行固定。这些特性对于展现数据,报表等是非常友好的一种用户体验。

今天我们不谈elTable的使用,今天我们来谈一谈elTable功能实现的原理。

image.png

第一步,我们就需要正常的展现这个table表格,td中的宽度用户设定多少就是多少,没设定就自动宽度。

第二步,通过js操作dom,获取到这个table中,每一行的高度,每一列的宽度。

第三步,实现table功能的的布局。

image.png

这样,我们table布局就实现了。简单点实现的话,每一个块内都放置整个table,然后定义定高或者定宽。超出部分不展示。

第四步,滚动条跟随滚动,如果有纵向滚动条,那么添加滚动事件,在滚动时,左侧,右侧固定列偏移对应的滚动值。横向滚动条类似。

第五步,gutter,比如出现纵向滚动条时,内容去的table宽度小了一个滚动条的宽度,那么头部固定表格需要添加一个空td,设置宽度为滚动条宽度,才能与内容区table对齐。计算方法就是内容去table外层div的offsetWidth - clientWidth得到滚动条的宽度。

image.png

gutter就是上图红框区域。


综上所述,elementUI的elTable实现原理就是上面这几步骤。


用途

Vue中JSX使用绘制报表,此文章处就是一个使用的地方,对于复杂报表,不管是elementUI table,还是vxe-table都显得无能为力。这时候我们就可以使用更加灵活强大的render函数来实现功能了。

但是如果客户需要表头固定,那么我们就需要用到上面的知识了。

image.png

运用上述知识,我们就可以轻松实现表头固定的功能。

<script>
export default{
    props:{
        lists:{
            type:Array,
            default:()=>{
                return [];
            }
        },
        tps:{
            type:Array,
            default:()=>{
                return ['银川','吴忠','石嘴山','中卫','宁东','固原'];
            }
        },
        //前五名加背景色
        five:{
            type:Boolean,
            default:false
        }
    },
    data(){
        return {
            gutter:0,
        }
    },
    computed:{
        dobleList(){
            let arr = [];
            for(let i =0 ;i<this.lists.length;i++){
                arr.push(this.lists[i]);
                arr.push(this.lists[i]);
            }
            return arr;
        }
    },
    mounted(){
        setTimeout(()=>{
            this.$nextTick(()=>{
                this.calGutter();
            });
        },500);
        
    },
    methods:{
        calGutter(){
            let cht = this.$refs.cont.clientHeight;
            
            let tht = this.$refs.tbs.offsetHeight;
            let owd = this.$refs.cont.offsetWidth;
            let cwd = this.$refs.cont.clientWidth;
            if(tht<=cht){
                this.gutter = 0;
            }else{
                this.gutter =( owd - cwd -2) + 'px'
            }

        },
        gettClass(it,k){
            let cstr = '';
            if(it.value&&it.value.length>k){
                if(it.value[k].zbpm==1){
                    cstr = 'rp-first';
                } else if (this.five){
                    switch(it.value[k].zbpm){
                        case 2: 
                        case 3: 
                        case 4: 
                        case 5: cstr = 'rp-two';
                    }
                }
            }
            return cstr;
        }
    },
    render(){
        return (
            <div style="height:100%;position:relative;">
            <div class="rp-noscroll">
                <table style="width:100%;border:1px solid #D9D9D9;border-collapse:collapse;" class="rp-table" border >
                <tr>
                    <th colspan="3" class="rp-header">&nbsp;&nbsp;</th>
                    {
                        this.tps.map(it=>{
                            return <th class="rp-header">{it}</th>
                        })
                    }
                    {
                        this.gutter!=0?<th width={this.gutter}></th>:""
                    }
                    
                </tr>
                {
                    
                    this.dobleList.map((it,i)=>{
                        if(i%2==0){
                            return (
                                    <tr>
                                        {
                                            i/2==1?<td rowspan={(this.lists.length-1)*2+''}>专业管理</td>:""
                                        }
                                        <td rowspan="2" >{ it.dwmc }</td>
                                        <td colspan={i/2==0?2:1}>得分</td>
                                        {
                                            this.tps.map((t,k)=>{
                                                return <td >
                                                        {
                                                            it.value&&it.value.length>k?it.value[k].zbdf:""
                                                        }
                                                        </td>
                                            })
                                        }
                                        {
                                            this.gutter>0?<th width={this.gutter}></th>:""
                                        }
                                    </tr>
                                    
                            )
                        }else{
                            return (
                                <tr>
                                        
                                        <td colspan={(i-1)/2==0?2:1}>排名</td>
                                        {
                                            this.tps.map((t,k)=>{
                                                return <td >
                                                        {
                                                            it.value&&it.value.length>k?it.value[k].zbpm:""
                                                        }
                                                        </td>
                                            })
                                        }
                                        {
                                            this.gutter!=0?<th width={this.gutter}></th>:""
                                        }
                                    </tr>
                            )
                        }
                    })
                    
                }
                
            </table>
            </div>
            <div style="height:100%;overflow:auto;" ref="cont">
            <table style="width:100%;border:1px solid #D9D9D9;border-collapse:collapse;" ref="tbs" class="rp-table" border >
                <tr>
                    <th colspan="3" class="rp-header">&nbsp;&nbsp;</th>
                    {
                        this.tps.map(it=>{
                            return <th class="rp-header">{it}</th>
                        })
                    }
                </tr>
                {
                    
                    this.dobleList.map((it,i)=>{
                        if(i%2==0){
                            return (
                                    <tr>
                                        {
                                            i/2==1?<td rowspan={(this.lists.length-1)*2+''}>专业管理</td>:""
                                        }
                                        <td rowspan="2" >{ it.dwmc }</td>
                                        <td colspan={i/2==0?2:1}>得分</td>
                                        {
                                            this.tps.map((t,k)=>{
                                                return <td >
                                                        {
                                                            it.value&&it.value.length>k?it.value[k].zbdf:""
                                                        }
                                                        </td>
                                            })
                                        }
                                    </tr>
                                    
                            )
                        }else{
                            return (
                                <tr>
                                        
                                        <td colspan={(i-1)/2==0?2:1}>排名</td>
                                        {
                                            this.tps.map((t,k)=>{
                                                return <td class={this.gettClass(it,k)}>
                                                        {
                                                            it.value&&it.value.length>k?it.value[k].zbpm:""
                                                        }
                                                        </td>
                                            })
                                        }
                                    </tr>
                            )
                        }
                    })
                    
                }
                
            </table>
            </div>
            </div>
        )
    }
}
</script>

完整表头固定代码如上,我是采用了第二种方式,表头区域渲染了整个table的备份,只是设置了固定高度截图表头部分。算是偷懒的实现吧。

 /* 报表样式 */
 .rp-header{background:#e1e1e1;}
 .rp-table th,.rp-table td{text-align:center;line-height: 28px;font-size:13px;color:#0E0E0E;}
 .rp-noscroll{height:29px;overflow:hidden;top:0;left:0;right:0;position:absolute;z-index: 2;}
 .rp-table td.rp-first{background:#00A187;color:#fff;font-weight:bolder;}
 .rp-table td.rp-two{background:#31E4C7;color:#fff;}

样式只要通过absolute定位就可以实现了。

希望此文章对你能有所帮助。

原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(1675)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1