最近在用element-ui遇到一些bug,在使用el-select时,数据量大了就页面渲染缓慢从而卡顿严重,为了解决这个问题,对element-ui进行了改造,el-select改为分页滚动加载:

 如上图所示的效果,大数据时下拉可以分页滚动加载,而且可以支持原来的搜索。

1.新建一个selectSearch.vue页面子组件,页面内容如下:

<template>
    <div>

        <div class="selectBox" v-clickoutside="handleClose">
            <i class="icon el-icon-arrow-down " :class="showdrop?'arrowtop':''"></i>
            <input type="text" :placeholder="$t('pageinfo.searchstore')"
                   ref="searchInput"
                   v-model="selectData.storeName"
                   @focus="showdropbox"
                   @blur="closedropbox"
                   @input="selectInput"
                    />
            <transition name="el-zoom-in-top">
                <div class="dropdown" v-if="showdrop" v-el-select-loadmore="load">
                    <div class="arrow"></div>
                    <div class="contentMore" v-show="loadTextBox" :style="storeidlist.length>7?'height:250px;':(storeidlist.length===0?'height:46px':'height:'+(storeidlist.length*34+12)+'px;')">
                        <el-scrollbar  style="height: 100%;max-height:250px;" ref="myscroll" class="myscroll" >
                            <ul  >
                                <li v-for="store in storeidlist" :class="store.storeId === SelectValue.storeId ?'selected ':''"
                                    @click="selectOne(store)">{{store.storeName}}</li>

                                <li v-if="storeidlist.length==0" style="display: inline-block;">{{$t('pageinfo.nosearchdata')}}</li>
                            </ul>
                        </el-scrollbar>
                    </div>

                </div>
            </transition>
        </div>
    </div>
</template>

<script>
    import Clickoutside from './../../utils/clickoutside';

    export default {
        directives: {
            'el-select-loadmore': {
                bind(el, binding) {
                    const SELECTWRAP_DOM = el.querySelector(
                        '.contentMore .myscroll .el-scrollbar__wrap'
                    );
                    SELECTWRAP_DOM.addEventListener('scroll', function() {
                        const condition =
                            this.scrollHeight - this.scrollTop <= this.clientHeight;

                        if (condition) {
                            binding.value()
                        }
                    })
                }
            },
            Clickoutside,
        },
        name: "StoreSelectSearch",
        data(){
            return{
                selectData:{
                    storeId:1627479325921,
                    storeName:"default",
                    externalStoreId:null,
                },
                SelectValue:{
                    storeId:1627479325921,
                    storeName:"default",
                    externalStoreId:null,
                },
                changeSelect:false,
                showdrop:false,
                inputshow:false,
                storeidlistall:[],
                storeidlist:[], //显示或搜索出的数据

                loadPage:{
                    pageSize:200,
                    currentPage:1,
                },
                loadTextBox:true,

            }
        },
        mounted(){
            if(sessionStorage.getItem('STORELIST')){
                let allstorelist = JSON.parse(sessionStorage.getItem('STORELIST'));
                this.storeidlistall =  JSON.parse(JSON.stringify(allstorelist));
                this.storeidlist = JSON.parse(JSON.stringify(allstorelist.slice(0,this.loadPage.pageSize)));
                this.selectData = JSON.parse(JSON.stringify(allstorelist[0]));
                this.SelectValue = JSON.parse(JSON.stringify(allstorelist[0]));
            }else{
                console.log('loading getDataPermissions');
                this.getStorelist().then(res=> {
                    if(res.success){
                        let allstorelist = res.data;
                        this.storeidlistall =  JSON.parse(JSON.stringify(allstorelist));
                        this.storeidlist = JSON.parse(JSON.stringify(allstorelist.slice(0,this.loadPage.pageSize)));
                        this.selectData = JSON.parse(JSON.stringify(allstorelist[0]));
                        this.SelectValue = JSON.parse(JSON.stringify(allstorelist[0]));

                    }
                });
            }

        },
        methods:{
            //获取焦点打开
            showdropbox(){
                this.$refs.searchInput.setAttribute("placeholder",JSON.parse(JSON.stringify(this.selectData.storeName)));
                this.selectData ={};
                this.showdrop = true;
                this.changeSelect = false; //未选择值
                this.loadPage.currentPage = 1;
                this.storeidlist = JSON.parse(JSON.stringify(this.storeidlistall.slice(0,this.loadPage.pageSize)));


            },
            //元素外的点击()替代离焦事件,解决点击选择冲突
            handleClose(){

                setTimeout(()=>{
                    //console.log('外外外外外外');
                    this.showdrop = false;
                    if( !this.changeSelect ){
                        this.selectData =JSON.parse(JSON.stringify(this.SelectValue));
                    }

                },50);
            },
            //失去焦点
            closedropbox(){
                /*setTimeout(()=>{
                    console.log('失去焦点')
                    this.showdrop = false;
                    if( !this.changeSelect ){
                        this.selectData =JSON.parse(JSON.stringify(this.SelectValue));
                    }

                },250);*/
            },
            //点击选择并关闭下拉
            selectOne(one){
                console.log('选择');
                this.selectData = JSON.parse(JSON.stringify(one));
                this.showdrop = false;
                this.changeSelect = true; //已选择值

                setTimeout(()=>{
                    this.SelectValue = JSON.parse(JSON.stringify(this.selectData));

                    this.$emit('changedata',JSON.parse(JSON.stringify(this.selectData)).storeId);
                },10)
            },
            //输入的值
            selectInput(val){
               //console.log('搜索',val,this.$refs.searchInput.value);
               //this.loadTextBox = false;
                if(this.$refs.searchInput.value){
                    this.storeidlist = [];
                    this.storeidlist = this.storeidlistall.filter((one)=>{
                        if(one.storeName.indexOf(this.$refs.searchInput.value)>-1 || String(one.externalStoreId).indexOf(this.$refs.searchInput.value)>-1){
                            return true;
                        }
                    });
                    let total = this.storeidlistall.length;
                    this.loadPage.currentPage = Math.ceil(total/this.loadPage.pageSize) ; //页码大于最大值则无需滚动加载
                }else{
                    this.loadPage.currentPage = 1;
                    this.storeidlist = JSON.parse(JSON.stringify(this.storeidlistall.slice(0,this.loadPage.pageSize)));
                }
                /*setTimeout(()=>{
                    this.loadTextBox = true; //解决滚动条不会跟着内容变化的问题
                },100);*/

            },
            //分页请求load
            load () {
                console.log('load');

                let total = this.storeidlistall.length;
                if(total/this.loadPage.pageSize<this.loadPage.currentPage){
                    return;
                }
                console.log(total/this.loadPage.pageSize,this.loadPage.currentPage);

                this.loadPage.currentPage++;
                this.storeidlist = [... this.storeidlist,...JSON.parse(JSON.stringify(
                    this.storeidlistall.slice((this.loadPage.currentPage-1)*this.loadPage.pageSize,
                        this.loadPage.currentPage*this.loadPage.pageSize )))];

            }
        }

    }
</script>

<style scoped lang="scss">
.selectBox{
    width: 200px;
    height: 26px;
    position: relative;

    .icon{
        position: absolute;
        right: 10px;
        top:10px;
        color:#C0C4CC;
        transition: all 0.5s;
        font-size: 14px;

        &.arrowtop{
            transition: all 0.5s;
            transform: rotate(-180deg);
        }
    }

    .dropdown{
        position: absolute;
        top:40px;
        z-index: 999;
        min-width: 200px;
        background: #fff;
        border: 1px solid #E4E7ED;
        border-radius: 4px;
        box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
        padding: 8px 0 2px;

        .el-select-dropdown .el-scrollbar {padding-bottom: 17px;}
        .contentMore{
            width: 200px;
            height:250px;
        }
        ul{
            box-sizing: border-box;
            display: block;
            margin-bottom: 12px;

            li{
                font-size: 14px;
                position: relative;
                white-space: nowrap;
                padding: 5px 16px;
                overflow: hidden;
                text-overflow: ellipsis;
                color: #606266;
                height: 34px;
                line-height: 26px;
                -webkit-box-sizing: border-box;
                box-sizing: border-box;
                cursor: pointer;
                text-align: left;

                &:hover{
                    background: #F5F7FA;
                }
                &.selected{
                    color: #0062B2;
                    font-weight: 700;
                }
            }
        }

        .arrow{
            position: absolute;
            top: -6px;
            left: 35px;
            margin-right: 3px;
            border-bottom-color: #EBEEF5;
            border-width: 6px;
            -webkit-filter: drop-shadow(0 2px 12px rgba(0, 0, 0, .03));
            filter: drop-shadow(0 2px 12px rgba(0, 0, 0, .03));

            &:after{
                content: " ";
                border-width: 6px;
                position: absolute;
                display: block;
                width: 0;
                height: 0;
                border-color: transparent;
                border-style: solid;

                top: 1px;
                margin-left: -6px;
                border-top-width: 0;
                border-bottom-color: #FFF;
            }
        }
    }

    input{
        -webkit-appearance: none;
        width: 100%;
        height:100%;
        border:1px solid #DCDFE6;
        outline: 0;
        border-radius: 2px;
        text-indent: 16px;
        transition: all 0.5s;
        cursor: pointer;
        /*background: #F5F7FA;*/
        color: #606266;
        font-size: 12px;
        background: rgba(255,255,255,0.1);

        &:hover{
            border:1px solid #C0C4CC;
        }
        &:focus{
            border:1px solid #0062B2;
        }
        &:active{
            border:1px solid #C0C4CC;
        }
        &:visited{
            border:1px solid #0062B2;
        }

        input::-webkit-input-placeholder{
            color:#C0C4CC;
        }
        input::-moz-placeholder{   /* Mozilla Firefox 19+ */
            color:#C0C4CC;
        }
        input:-moz-placeholder{    /* Mozilla Firefox 4 to 18 */
            color:#C0C4CC;
        }
        input:-ms-input-placeholder{  /* Internet Explorer 10-11 */
            color:#C0C4CC;
        }
    }

}
</style>

我就把新造的组件直接pu上来了,看不懂的地方没关系,只是业务中的部分逻辑在里面,能看懂的地方直接抄,哈哈。

下次再来编辑一下做详细说明。。

2.页面引入:

js引入:

import SelectSearch from '@/components/come/SelectSearch'


components: {
    SelectSearch
},


html引入:

 <SelectSearch @changedata="changestore"></SelectSearch>

changestore:{
//回调选择的结果
}

以上就是放element-ui制作的升级版,下拉搜索+分页滚动的组件啦~~

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐