如何在Google Optimize A/B测试中让Shopify加购弹窗永久显示
Shopify加购弹窗永久显示方案(Google Optimize A/B测试场景)
问题背景
我正在用Google Optimize给Shopify站点做A/B测试,当前加购弹窗仅显示5秒就自动关闭,需要让它永久保留。原本可以直接修改theme.js里的popdown函数(该函数通过5秒setTimeout移除控制弹窗显示的is-visible类),但没有权限操作这个文件。尝试过用CSS和JS修改弹窗可见性,Chrome开发者工具显示计算样式为visible但实际不生效;也尝试修改Product类的initAdd方法,但无法访问实际调用的实例,所有尝试均失败,求可行解决方法。
相关代码片段(theme.js)
Product.prototype = _.assignIn({}, Product.prototype, { init: function () { theme.mediaInstances[this.id] = new theme.Media(this.container); theme.mediaInstances[this.id].init(); }, initAdd: function () { var $drawer = $(this.selectors.addDrawerWrapper), source = $(this.selectors.addDrawerTemplate).html(), template = Handlebars.compile(source), globalTimer; $("[data-add-to-cart]").on("click", function (e) { var isFocusEnabled = $("body").hasClass("focus-enabled"); if (isFocusEnabled) { return; } e.preventDefault(); var form = $(this).closest("form"), form_serialized = form.serializeArray(); if (form.find('[type="file"]').length) { return; } var form_object = {}; $.map(form_serialized, function (val, i) { form_object[val.name] = val.value; }); ajaxAddItem(form_object); }); var ajaxAddItem = function (data) { $.ajax({ type: "POST", url: "/cart/add.js", dataType: "json", data: data, error: addError, success: addSuccess, complete: updateHeaderTotal, }); }; var updateHeaderTotal = function () { $.getJSON("/cart.js").done(function (cart) { var newTotal = slate.Currency.formatMoney( cart.total_price, theme.moneyFormat ); $(".cartCost") .html("(<span class='money'>" + newTotal + "</span>)") .removeClass("hidden-count"); }); }; var addError = function (object, status) { var errors = '<div class="errors">' + object.responseJSON.description + "</div>"; $drawer.empty(); $drawer.append(errors); $drawer.addClass("has-errors is-visible"); popdown(); }; var addSuccess = function (product) { productObject = { product_title: product.product_title, product_image: product.image, variant: product.variant_title == "Default Title" ? false : product.variant_title, quantity: product.quantity, price: slate.Currency.formatMoney(product.price, theme.moneyFormat), }; $drawer.empty(); $drawer.append(template(productObject)); // Popover should be just below header var topPosition = $(".site-header").outerHeight() + $(".info-bar").outerHeight(); $drawer.attr("style", ""); // If it is sticky, just put it at the header height with position: fixed if ($(".header__wrapper").hasClass("header--sticky")) { var topPosition = $(".site-header ").outerHeight(); $drawer.css("top", topPosition); } else if ($(window).scrollTop() > topPosition) { // header is not visible pin to top $drawer.css("top", 0); $drawer.css("z-index", "2000"); } else { // otherwise positon: absolute below header // or at top if scrolled below header topPosition = Math.max($(window).scrollTop(), topPosition); $drawer.css("position", "absolute"); $drawer.css("top", topPosition); } $drawer.addClass("is-visible"); popdown(); }; var popdown = function () { clearTimeout(globalTimer); globalTimer = setTimeout(function () { $drawer.removeClass("is-visible").removeClass("has-errors"); }, 5000); }; $drawer.on("click", ".close", function () { $drawer.removeClass("is-visible").removeClass("has-errors"); }); } });
可行解决方案
方案1:拦截弹窗关闭定时器
核心思路是阻止popdown函数里的setTimeout执行,或者在弹窗显示后立即清除该定时器。可以将以下代码添加到Google Optimize变体的自定义JS中:
document.addEventListener('DOMContentLoaded', () => { // 替换为你站点弹窗的实际选择器,比如原代码里的this.selectors.addDrawerWrapper对应的选择器 const drawer = document.querySelector('.add-to-cart-drawer'); if (!drawer) return; // 监听弹窗类变化,显示时清除所有可能的关闭定时器 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.attributeName === 'class' && drawer.classList.contains('is-visible')) { // 清除所有定时器(范围足够覆盖弹窗的定时器ID) for (let i = 0; i < 1000; i++) clearTimeout(i); } }); }); observer.observe(drawer, { attributes: true }); // 额外:重写setTimeout,直接跳过移除is-visible的定时器 const originalSetTimeout = window.setTimeout; window.setTimeout = function(callback, delay) { if (typeof callback === 'function' && callback.toString().includes('removeClass("is-visible")')) { return null; // 不创建这个定时器 } return originalSetTimeout(callback, delay); }; });
方案2:强制锁定弹窗可见状态
通过高优先级CSS强制弹窗显示,配合JS阻止is-visible类被移除:
自定义CSS(Google Optimize中添加)
.add-to-cart-drawer.is-visible { display: block !important; opacity: 1 !important; visibility: visible !important; }
自定义JS(Google Optimize中添加)
document.addEventListener('DOMContentLoaded', () => { const drawer = document.querySelector('.add-to-cart-drawer'); if (!drawer) return; // 监听类变化,一旦is-visible被移除就重新加上 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.attributeName === 'class') { if (!drawer.classList.contains('is-visible')) { drawer.classList.add('is-visible'); } if (!drawer.classList.contains('has-errors')) { drawer.classList.add('has-errors'); } } }); }); observer.observe(drawer, { attributes: true }); // 可选:如果需要保留关闭按钮功能,注释下面的代码 const closeBtn = drawer.querySelector('.close'); if (closeBtn) { closeBtn.addEventListener('click', e => { e.preventDefault(); e.stopPropagation(); }); } });
方案3:重写Product.initAdd方法
覆盖原initAdd方法,去掉popdown()的调用,或者重新定义popdown为空函数:
document.addEventListener('DOMContentLoaded', () => { // 等待Product原型加载完成 setTimeout(() => { if (typeof Product === 'undefined') return; const originalInitAdd = Product.prototype.initAdd; Product.prototype.initAdd = function() { // 执行原方法逻辑 originalInitAdd.call(this); const $drawer = $(this.selectors.addDrawerWrapper); // 重新绑定加购按钮事件,在弹窗显示后清除定时器 $('[data-add-to-cart]').on('click', () => { setTimeout(() => { for (let i = 0; i < 1000; i++) clearTimeout(i); }, 100); }); }; }, 500); });
注意事项
- 替换代码中的
.add-to-cart-drawer为你站点弹窗的实际选择器(可通过Chrome开发者工具查看) - 所有代码需添加到Google Optimize对应变体的自定义代码区域,确保仅在测试组生效
- 测试时验证弹窗是否正常显示、加购功能是否不受影响
内容的提问来源于stack exchange,提问作者youngbloodcyb
相关产品推荐
相关产品推荐

