You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:07:00