高度自適應(yīng)與狀態(tài)持久化解決方案)
在前端開發(fā)中使用 Layui 的carousel輪播圖擴(kuò)展分步表單時(shí)經(jīng)常會(huì)遇到以下三大痛點(diǎn)隱藏步驟不顯示/高度塌陷切換到 Step 3 或后續(xù)步驟時(shí)因 DOM 處于隱藏狀態(tài)導(dǎo)致高度計(jì)算為0內(nèi)容無法正常顯示。性能警告Forced reflow頻繁手動(dòng)獲取scrollHeight并設(shè)置 CSSheight觸發(fā)瀏覽器的強(qiáng)制重排。刷新后狀態(tài)丟失頁面刷新后默認(rèn)重置到第一步用戶體驗(yàn)不佳。本文提供一套完整的重構(gòu)方案采用原生ResizeObserver實(shí)現(xiàn)無感高度自適應(yīng)并結(jié)合localStorage與URL參數(shù)實(shí)現(xiàn)無縫狀態(tài)刷新。1、預(yù)覽圖首先導(dǎo)入擴(kuò)展 js和css 文件可以直接引用官網(wǎng)里面的js或者本地資源位置【免費(fèi)】step步驟表單分步表單測試測試測試資源-CSDN文庫一、 CSS 樣式修復(fù)/* 覆蓋 Layui Carousel 的固定高度限制 */ #stepForm, #stepForm [carousel-item], #stepForm [carousel-item] div { height: auto !important; min-height: 380px; /* 設(shè)置底線防塌陷 */ } /* 控制步驟內(nèi)容的顯隱徹底解決切到 Step 3 內(nèi)容不顯示的問題 */ #stepForm [carousel-item] div { display: none; } #stepForm [carousel-item] div.layui-this { display: block !important; }二、 步驟擴(kuò)展組件優(yōu)化 (step.js)重構(gòu)step.js增加精準(zhǔn)跳轉(zhuǎn)接口goStep()并處理好頭部 DOM 的響應(yīng)式同步。layui.define([layer, carousel], function (exports) { var $ layui.jquery; var carousel layui.carousel; // 渲染頭部步驟條 DOM var renderDom function (elem, stepItems, postion) { $(elem).find(.lay-step).remove(); var stepDiv div classlay-step; for (var i 0; i stepItems.length; i) { stepDiv div classstep-item; // 步驟連接線 if (i (stepItems.length - 1)) { var lineClass i postion ? step-item-tail-done : ; stepDiv div classstep-item-taili class lineClass /i/div; } // 節(jié)點(diǎn)數(shù)字與狀態(tài)圖標(biāo) var number stepItems[i].number || (i 1); if (i postion) { stepDiv div classstep-item-head step-item-head-activei classlayui-icon number /i/div; } else if (i postion) { stepDiv div classstep-item-head step-item-head-donei classlayui-icon layui-icon-ok/i/div; } else { stepDiv div classstep-item-headi classlayui-icon number /i/div; } // 標(biāo)題和描述 var title stepItems[i].title || ; var desc stepItems[i].desc || ; if (title || desc) { stepDiv div classstep-item-main; if (title) stepDiv div classstep-item-main-title title /div; if (desc) stepDiv div classstep-item-main-desc desc /div; stepDiv /div; } stepDiv /div; } stepDiv /div; $(elem).prepend(stepDiv); var bfb 100 / stepItems.length; $(.step-item).css(width, bfb %); }; var step { render: function (param) { param.indicator none; param.arrow none; param.autoplay false; var stepItems param.stepItems; var elem param.elem; // 渲染 Carousel carousel.render(param); // 渲染頭部 var initStep param.step || 0; renderDom(elem, stepItems, initStep); if (param.stepWidth) { $(elem).find(.lay-step).css(width, param.stepWidth); } // 監(jiān)聽輪播圖切換事件 carousel.on(change( param.filter ), function (obj) { renderDom(elem, stepItems, obj.index); if (param.stepWidth) { $(elem).find(.lay-step).css(width, param.stepWidth); } if (typeof param.stepChange function) { param.stepChange(obj.index); } }); // 隱藏默認(rèn)按鈕并去掉背景 $(elem).find(.layui-carousel-arrow).css(display, none); $(elem).css(background-color, transparent); }, // 跳轉(zhuǎn)指定步驟 goStep: function (elem, index) { var $elem $(elem); var items $elem.find([carousel-item] div); if (index 0 || index items.length) return; items.removeClass(layui-this).eq(index).addClass(layui-this); $elem.find(.layui-carousel-ind li).eq(index).trigger(click); }, next: function (elem) { var currentIndex $(elem).find([carousel-item] div.layui-this).index(); this.goStep(elem, currentIndex 1); }, pre: function (elem) { var currentIndex $(elem).find([carousel-item] div.layui-this).index(); this.goStep(elem, currentIndex - 1); } }; exports(step, step); });三、 主頁面邏輯實(shí)現(xiàn)在主頁面中利用ResizeObserver代替手動(dòng)的 DOM 高度計(jì)算邏輯無需在展開/收縮等事件里重復(fù)手動(dòng)調(diào)用調(diào)整高度的方法。script layui.config({ base: ./step-lay/ }).use([form, step, jquery], function () { var $ layui.jquery, form layui.form, step layui.step; // 1. 讀取步驟優(yōu)先 URL 參數(shù)其次 LocalStorage var urlParams new URLSearchParams(window.location.search); var savedStep parseInt(localStorage.getItem(currentStepIndex)) || 0; var currentStep parseInt(urlParams.get(step)) || savedStep; // 2. 初始化分步表單 step.render({ elem: #stepForm, filter: stepForm, width: 100%, stepWidth: 92%, stepItems: [ { title: 閱讀須知 }, { title: 填寫信息 }, { title: 上傳材料 }, { title: 結(jié)果領(lǐng)取 }, { title: 申請(qǐng)成功 } ], step: currentStep, stepChange: function (index) { // 同步保存到 LocalStorage 并更新 URL 參數(shù) localStorage.setItem(currentStepIndex, index); var url new URL(window.location.href); url.searchParams.set(step, index); window.history.replaceState({}, , url.toString()); // 觸發(fā)容器高度自適應(yīng)更新 updateContainerHeight(); } }); // 初始跳至對(duì)應(yīng)步驟 if (currentStep 0) { step.goStep(#stepForm, currentStep); } // 3. 表單事件綁定 form.on(submit(formStep), function () { step.next(#stepForm); return false; }); $(.pre).click(function () { step.pre(#stepForm); }); // 4. 高度實(shí)時(shí)自適應(yīng)機(jī)制 function updateContainerHeight() { var $activeItem $(#stepForm [carousel-item] div.layui-this); if ($activeItem.length 0) { var activeHeight $activeItem.outerHeight(true); $(#stepForm, #stepForm [carousel-item]).css(height, activeHeight px); } } // 利用 ResizeObserver 自動(dòng)感知頁面內(nèi)容高度變動(dòng)折疊、展開、異步渲染等 if (ResizeObserver in window) { var observer new ResizeObserver(function () { updateContainerHeight(); }); $(#stepForm [carousel-item] div).each(function () { observer.observe(this); }); } else { // 兜底方案 setInterval(updateContainerHeight, 300); } }); // 內(nèi)容展開/收縮控制函數(shù)ResizeObserver 會(huì)自動(dòng)響應(yīng)尺寸變化無需手動(dòng)計(jì)算高度 function toggleContent(divId, toggleImage) { var contentDiv document.getElementById(divId); if (contentDiv.style.display none) { contentDiv.style.display block; toggleImage.src ../image/收縮.png; } else { contentDiv.style.display none; toggleImage.src ../image/展開.png; } } /script