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

Shopify主题应用扩展中Liquid代码段异步渲染问题求助

问题:无法将JavaScript变量赋值给Shopify Liquid并实现异步渲染

我调用后端API后想渲染Shopify产品,但没法把JavaScript变量赋值给Shopify Liquid文件。以下是我的代码:

<script async defer>
  const BACKEND_SHOPIFY_URL="/apps/client/upsells";
      (async()=>{
        try {
          const response =  await fetch(`${BACKEND_SHOPIFY_URL}?position={{ position }}`);
          const data= await response.json();
          {% assign result= "SOMETHING HERE" %}        // 需要把result赋值为data
          }
        catch(err) {
            console.log(err,'error');
              }
      })();
</script>

我试过各种方法都没成功,想请教:

  1. 如何实现异步渲染?
  2. 了解到fetch过滤器,但不确定怎么在主题应用扩展中导入?
  3. 既然JavaScript是客户端语言,Liquid是服务端语言,有没有办法重新渲染特定组件?

解决方案

核心原理说明

Liquid是服务端渲染语言,在服务器生成页面HTML时就已经执行完毕;而JavaScript是客户端语言,要等页面加载到浏览器后才会运行。两者完全不在同一执行阶段,所以不可能直接把客户端JS变量赋值给Liquid变量,必须换思路实现需求。

方案1:客户端JS动态渲染DOM

这是最直接的异步渲染方案,步骤如下:

  1. 在页面上预留一个用于渲染产品的容器
  2. 调用API拿到数据后,用JS动态生成产品的HTML结构,插入到容器中

示例代码:

<!-- 预留容器 -->
<div id="upsell-products-container"></div>

<script async defer>
  const BACKEND_SHOPIFY_URL = "/apps/client/upsells";
  const container = document.getElementById('upsell-products-container');
  
  (async () => {
    try {
      const response = await fetch(`${BACKEND_SHOPIFY_URL}?position={{ position }}`);
      const data = await response.json();
      
      // 动态生成产品卡片HTML(结构可参考主题现有产品卡片)
      let productsHtml = '';
      data.forEach(product => {
        productsHtml += `
          <div class="product-card">
            <a href="${product.url}">
              <img src="${product.image.src}" alt="${product.title}">
              <h3>${product.title}</h3>
              <span class="price">${product.price}</span>
            </a>
          </div>
        `;
      });
      
      container.innerHTML = productsHtml;
    } catch(err) {
      console.log(err, 'error');
      container.innerHTML = '<p>推荐商品加载失败</p>';
    }
  })();
</script>

方案2:使用Liquid的fetch过滤器(服务端获取数据)

Liquid自带的fetch过滤器是服务端请求工具,和客户端JS的fetch不是一回事,它能在页面渲染阶段就获取API数据,不需要客户端异步请求。

在主题应用扩展中可以直接使用,无需额外导入,示例:

{% comment %} 服务端调用API获取数据 {% endcomment %}
{% assign api_url = '/apps/client/upsells?position=' | append: position %}
{% assign upsell_data = api_url | fetch %}
{% assign upsell_products = upsell_data | json %}

{% comment %} 用Liquid直接渲染产品 {% endcomment %}
<div class="upsell-products">
  {% for product in upsell_products %}
    <div class="product-card">
      <a href="{{ product.url }}">
        <img src="{{ product.image.src }}" alt="{{ product.title }}">
        <h3>{{ product.title }}</h3>
        <span class="price">{{ product.price }}</span>
      </a>
    </div>
  {% endfor %}
</div>

注意:此方案要求后端API允许Shopify服务器发起请求(无CORS限制、认证逻辑兼容服务端调用)。

重新渲染特定组件的方法

页面加载后无法重新执行Liquid代码,要重新渲染组件只能通过客户端JS实现:

  • 方法一:重新调用API获取数据,再重新生成DOM结构替换原有内容
  • 方法二:提前用<template>标签存储Liquid生成的产品卡片模板,后续用JS克隆模板并填充新数据

示例模板方式代码:

<!-- 预存产品卡片模板 -->
<template id="product-card-template">
  <div class="product-card">
    <a href="">
      <img src="" alt="">
      <h3></h3>
      <span class="price"></span>
    </a>
  </div>
</template>

<!-- 渲染容器 -->
<div id="upsell-products-container"></div>

<script async defer>
  const BACKEND_SHOPIFY_URL = "/apps/client/upsells";
  const container = document.getElementById('upsell-products-container');
  const template = document.getElementById('product-card-template');
  
  async function renderUpsellProducts(position) {
    try {
      const response = await fetch(`${BACKEND_SHOPIFY_URL}?position=${position}`);
      const data = await response.json();
      
      // 清空容器
      container.innerHTML = '';
      
      // 克隆模板并填充数据
      data.forEach(product => {
        const card = template.content.cloneNode(true);
        card.querySelector('a').href = product.url;
        card.querySelector('img').src = product.image.src;
        card.querySelector('img').alt = product.title;
        card.querySelector('h3').textContent = product.title;
        card.querySelector('.price').textContent = product.price;
        container.appendChild(card);
      });
    } catch(err) {
      console.log(err, 'error');
      container.innerHTML = '<p>推荐商品加载失败</p>';
    }
  }

  // 首次渲染
  renderUpsellProducts({{ position }});
  
  // 后续需要重新渲染时调用:比如用户切换位置后
  // renderUpsellProducts(newPosition);
</script>

内容的提问来源于stack exchange,提问作者Sanjiv Gautam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:45:46