生产需求是后台配置的5700多条医院检查项目数据,存在一个配置项里,一次查出所有数据的字符串拼接,无法在后端分页,只能一次性返回给前端处理。一次渲染5700多条数据的dom,浏览器卡了30秒左右,几乎算崩了(以我的电脑配置来看),只能做成滚动分批加载,在html里插入一部分vue3来实现的。
数据渲染为checkbox多选框,因为是部分插入vue3,所以代码包含和外部html逻辑交互的部分。做个笔记!

html部分:

<div id="app">
    <div class="mask fadeIn jcxm-mask" v-if="showjc">

        <div class="all-label">
            <div class="back" @click="hideJc()">« 返回</div>
            <div class="search layui-input-wrap">
                <input type="text"  placeholder="搜索…" class="layui-input" name="search" onblur="resetSearch()">
                <div class="layui-input-suffix" @click="searchLabel()">
                    <i class="layui-icon layui-icon-search"></i>
                </div>
            </div>
            <div class="jc-items" ref="scrollRef" @scroll.passive="handleScroll">
                <label v-for="(item,index) in visibleData" :key="index">
                    <input type="checkbox" name="extname" class="checkbox" :value="item" @click="changejc(index,item)">{{item}}
                </label>
                <div v-if="loading" class="loading-indicator center">⏳ 加载中...</div>
                <div v-else-if="isComplete" class="end-marker center">✅ 已加载全部数据</div>
            </div>
            <div class="btns text-right">
                <div class="btn cancel d-inline" @click="hideJc()">取消</div>
                <div class="btn confirm d-inline" @click="confirmJc()">确定</div>
            </div>
        </div>

    </div>
</div> 

JS部分:

const { createApp, ref, onMounted,computed,onUnmounted } = Vue
setup() {
       const showjc = ref(true)
        const list = ref([])
        const batchSize = 100;
        const currentPage = ref(0);
        const loading = ref(false);
        const scrollRef = ref(null);
        const isComplete = ref(false);
        const selectdArr = ref([])

        function confirmJc(){
            console.log(111)
        }

        function hideJc(){
            showjc.value = false
            setTimeout(()=>{
                showjc.value = true
            },800)
        }

       //checkbox点选和取消
        function changejc(index,item){
            if(!selectdArr.value[index]){
                selectdArr.value[index] = item
            }else{
                selectdArr.value.splice(index, 1);
            }
        }

        const visibleData = computed(() => 
          list.value.slice(0, (currentPage.value + 1) * batchSize)
        );

        const handleScroll = () => {
          if (loading.value || isComplete.value) return;

          const container = scrollRef.value;
          if (!container) return;

          const { scrollTop, scrollHeight, clientHeight } = container;
          const shouldLoad = scrollTop + clientHeight >= scrollHeight - 20;

          if (shouldLoad) {
            loadNextBatch();
          }
        };

        const loadNextBatch = async () => {
          loading.value = true;

          // 模拟异步加载
          await new Promise(resolve => setTimeout(resolve, 800));

          currentPage.value++;

          // 检查是否已加载全部数据
          if ((currentPage.value + 1) * batchSize >= list.value.length) {
            isComplete.value = true;
          }

          loading.value = false;
        };

        async function getvalues(){
            try {
              const response = await axios.post('/user/getValues',{extname:'ext_check'});
              list.value = response.data.data;
            } catch (error) {
              console.error(error);
            }
        }

        onMounted(() => {
            getvalues()
            window.addEventListener('resize', handleScroll);
        });
        onUnmounted(() => {
          // 清除可能存在的异步任务
          window.removeEventListener('resize', handleScroll);
        });

        return {
            showjc,
            confirmJc,
            list,
            visibleData,
            loading,
            isComplete,
            scrollRef,
            handleScroll,
            changejc
        }
    }

  }).mount('#app')