Codyhouse产品构建器单选按钮点击后持续加载问题求助
问题描述
我正在搭建一款产品构建器,使用Codyhouse的适配模板时遇到异常:点击单选按钮后,按钮始终处于加载状态,无法继续流程。修改过JS和CSS也未解决问题,怀疑是JS问题但无法确定。

相关JS代码
jQuery(document).ready(function($){ function ProductBuilder( element ) { this.element = element; this.stepsWrapper = this.element.children('.cd-builder-steps'); this.steps = this.element.find('.builder-step'); // 存储特定构建步骤 this.models = this.element.find('[data-selection="models"]'); this.summary; this.optionsLists = this.element.find('.options-list'); // 底部摘要栏 this.fixedSummary = this.element.find('.cd-builder-footer'); this.modelPreview = this.element.find('.selected-product').find('img'); this.totPriceWrapper = this.element.find('.tot-price').find('b'); // 构建器导航 this.mainNavigation = this.element.find('.cd-builder-main-nav'); this.secondaryNavigation = this.element.find('.cd-builder-secondary-nav'); // 标记构建器内容是否加载完成 this.loaded = true; // 绑定事件 this.bindEvents(); } ProductBuilder.prototype.bindEvents = function() { var self = this; // 左侧导航点击事件 this.mainNavigation.on('click', 'li:not(.active)', function(event){ event.preventDefault(); self.loaded && self.newContentSelected($(this).index()); }); // 底部固定导航点击事件 this.secondaryNavigation.on('click', '.nav-item li:not(.buy)', function(event){ event.preventDefault(); var stepNumber = ( $(this).parents('.next').length > 0 ) ? $(this).index() + 1 : $(this).index() - 1; self.loaded && self.newContentSelected(stepNumber); }); // 选项列表点击事件(如型号、配件) this.optionsLists.on('click', '.js-option', function(event){ self.updateListOptions($(this)); }); // 自定义控件点击事件(如颜色选择) this.stepsWrapper.on('click', '.cd-product-customizer a', function(event){ event.preventDefault(); self.customizeModel($(this)); }); }; ProductBuilder.prototype.newContentSelected = function(nextStep) { // 先检查是否已选择型号,未选择则无法继续导航 if( this.fixedSummary.hasClass('disabled') ) { // 未选择型号,显示提示 this.fixedSummary.addClass('show-alert'); } else { // 已选择型号,切换内容 // 如果当前是颜色选择步骤,更新底部预览图 if( this.steps.filter('.active').is('[data-selection="colors"]') ) { var imageSelected = this.steps.filter('.active').find('.cd-product-previews').children('.selected').children('img').attr('src'); this.modelPreview.attr('src', imageSelected); } // 如果切换到摘要步骤,更新摘要内容 if( nextStep + 1 >= this.steps.length ) { this.createSummary(); } this.showNewContent(nextStep); this.updatePrimaryNav(nextStep); this.updateSecondaryNav(nextStep); } } ProductBuilder.prototype.showNewContent = function(nextStep) { var actualStep = this.steps.filter('.active').index() + 1; if( actualStep < nextStep + 1 ) { // 切换到下一节 this.steps.eq(actualStep-1).removeClass('active back').addClass('move-left'); this.steps.eq(nextStep).addClass('active').removeClass('move-left back'); } else { // 切换到上一节 this.steps.eq(actualStep-1).removeClass('active back move-left'); this.steps.eq(nextStep).addClass('active back').removeClass('move-left'); } } ProductBuilder.prototype.updatePrimaryNav = function(nextStep) { this.mainNavigation.find('li').eq(nextStep).addClass('active').siblings('.active').removeClass('active'); } ProductBuilder.prototype.updateSecondaryNav = function(nextStep) { ( nextStep == 0 ) ? this.fixedSummary.addClass('step-1') : this.fixedSummary.removeClass('step-1'); this.secondaryNavigation.find('.nav-item.next').find('li').eq(nextStep).addClass('visible').removeClass('visited').prevAll().removeClass('visited').addClass('visited').end().nextAll().removeClass('visible visited'); this.secondaryNavigation.find('.nav-item.prev').find('li').eq(nextStep).addClass('visible').removeClass('visited').prevAll().removeClass('visited').addClass('visited').end().nextAll().removeClass('visible visited'); } ProductBuilder.prototype.createSummary = function() { var self = this; this.steps.each(function(){ // 根据构建步骤更新摘要内容,可按需修改 var step = $(this); if( $(this).data('selection') == 'colors' ) { // 生成颜色摘要 var colorSelected = $(this).find('.cd-product-customizer').find('.selected'), color = colorSelected.children('a').data('color'), colorName = colorSelected.data('content'), imageSelected = $(this).find('.cd-product-previews').find('.selected img').attr('src'); self.summary.find('.summary-color').find('.color-label').text(colorName).siblings('.color-swatch').attr('data-color', color); self.summary.find('.product-preview').attr('src', imageSelected); } else if( $(this).data('selection') == 'accessories' ) { var selectedOptions = $(this).find('.js-option.selected'), optionsContent = ''; if( selectedOptions.length == 0 ) { optionsContent = '<li><p>未选择任何配件;</p></li>'; } else { selectedOptions.each(function(){ optionsContent +='<li><p>'+$(this).find('p').text()+'</p></li>'; }); } self.summary.find('.summary-accessories').children('li').remove().end().append($(optionsContent)); } }); } ProductBuilder.prototype.updateListOptions = function(listItem) { var self = this; if( listItem.hasClass('js-radio') ) { // 单选类型(如型号),取消其他已选项 var alreadySelectedOption = listItem.siblings('.selected'), price = (alreadySelectedOption.length > 0 ) ? -Number(alreadySelectedOption.data('price')) : 0; // 如果当前选项已选中,取消时扣除对应价格;否则添加价格 ( listItem.hasClass('selected') ) ? price = -Number(listItem.data('price')) : price = Number(listItem.data('price')) + price; alreadySelectedOption.removeClass('selected'); listItem.toggleClass('selected'); // 非型号步骤才更新总价 (listItem.parents('[data-selection="models"]').length == 0) && self.updatePrice(price); } else { // 多选类型,切换当前选项状态并更新总价 var price = ( listItem.hasClass('selected') ) ? -Number(listItem.data('price')) : Number(listItem.data('price')); listItem.toggleClass('selected'); self.updatePrice(price); } // 如果是型号选项,更新构建器内容 if( listItem.parents('[data-selection="models"]').length > 0 ) { self.updateModelContent(listItem); } }; ProductBuilder.prototype.updateModelContent = function(model) { var self = this; if( model.hasClass('selected') ) { var modelType = model.data('model'), modelImage = model.find('img').attr('src'); // 更新底部预览图 this.modelPreview.attr('src', modelImage); // 移除其他型号内容,加载当前型号对应的内容 this.models.siblings('li').remove(); $.ajax({ type : "GET", dataType : "html", url : modelType+".html", beforeSend : function(){ self.loaded = false; model.siblings().removeClass('loaded'); }, success : function(data){ self.models.after(data); self.loaded = true; model.addClass('loaded'); // 激活导航 self.fixedSummary.add(self.mainNavigation).removeClass('disabled show-alert'); // 更新对象属性 self.steps = self.element.find('.builder-step'); self.summary = self.element.find('[data-selection="summary"]'); // 重新绑定选项列表点击事件 self.optionsLists.off('click', '.js-option'); self.optionsLists = self.element.find('.options-list'); self.optionsLists.on('click', '.js-option', function(event){ self.updateListOptions($(this)); }); // 移除首次加载动画标记 self.element.find('.first-load').removeClass('first-load'); }, error : function(jqXHR, textStatus, errorThrown) { // 此处可添加错误提示 } }); // 更新总价为当前型号价格 this.totPriceWrapper.text(model.data('price')); } else { // 取消型号选择,重置状态 this.fixedSummary.add(this.mainNavigation).addClass('disabled'); this.totPriceWrapper.text('0'); this.models.find('.loaded').removeClass('loaded'); } }; ProductBuilder.prototype.customizeModel = function(target) { var parent = target.parent('li') index = parent.index(); // 更新总价:如果当前选项已选中则价格不变,否则替换为当前选项价格 var price = ( parent.hasClass('selected') ) ? 0 : Number(parent.data('price')) - parent.siblings('.selected').data('price'); this.updatePrice(price); target.parent('li').addClass('selected').siblings().removeClass('selected').parents('.cd-product-customizer').siblings('.cd-product-previews').children('.selected').removeClass('selected').end().children('li').eq(index).addClass('selected'); }; ProductBuilder.prototype.updatePrice = function(price) { var actualPrice = Number(this.totPriceWrapper.text()) + price; this.totPriceWrapper.text(actualPrice); }; if( $('.cd-product-builder').length > 0 ) { $('.cd-product-builder').each(function(){ // 为每个产品构建器实例化对象 new ProductBuilder($(this)); }); } });
问题分析与修复方案
从代码和现象来看,单选按钮点击后一直处于加载状态的核心原因是:updateModelContent方法中的AJAX请求失败,但代码未处理错误状态,导致self.loaded一直为false,后续所有操作被阻塞。
具体修复步骤:
- 完善AJAX错误处理逻辑
在AJAX的error回调中重置加载状态,取消选中并提示用户:
error : function(jqXHR, textStatus, errorThrown) { self.loaded = true; model.removeClass('selected'); alert('模型内容加载失败,请检查文件路径或网络连接'); self.fixedSummary.add(self.mainNavigation).addClass('disabled'); }
验证文件路径正确性
确保AJAX请求的modelType+".html"文件存在,且路径与项目结构匹配(比如选中的型号data-model为"basic",则需存在basic.html文件)。调试请求状态
打开浏览器开发者工具(F12)→ Network标签,点击单选按钮查看请求状态码,确认是否是404(文件不存在)或其他网络错误。添加加载状态视觉反馈
可在beforeSend中给按钮添加加载样式,成功/失败后移除,让用户明确当前状态。
内容的提问来源于stack exchange,提问作者timharrymurphy
相关产品推荐
相关产品推荐

