标签搜索

在shopify站点上,每个section里,代码复用实例,该怎么优化?

sunshine
2025-10-28 / 0 评论 / 2 阅读

在 Shopify 里,一个 .liquid Section 就是一块「彼此独立、可重复、可排序」的积木。
核心限制是:

  1. 每个 Section 的代码最终会被 碎片式地 拼到同一个页面上;
  2. 不能保证 两个 Section 谁在前谁在后,也 不能保证 只出现一次;
  3. Shopify 没有「公共 JS 打包器」——不能 在 Section 里直接写 import 然后让主题统一去 type="module" 合并;
  4. 浏览器仍然 重复下载 同一个 CDN 地址,除非你用 nomodule/defer 做全局去重。

因此,「单模块复用」那一套在 Section 级别 是行不通的;必须把 Vue 3 当全局库来用,并且保证:

  • 只加载一次;
  • 每个 Section 只负责「自己挂载自己」;
  • 即使两个相同 Section 被拖到同一页面,也能各自独立运行。

下面给出 Shopify 官方推荐 的「Section-内自闭环 + 全局单例脚本」方案。


一、theme.liquid(或 head 标签里)统一引入 Vue 3

{%- comment -%} 仅当页面至少有一个需要 Vue 的 Section 时才加载 {%- endcomment -%}
{%- if request.page_type contains 'index' or section_blocks_contains_vendor 'vue' -%}
  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js" defer></script>
{%- endif -%}

说明

  • vue.global.prod.jsIIFE 版本,会把 Vue 暴露成全局 Vue;
  • defer 保证执行顺序在 DOM 解析之后,且 只下载一次
  • section_blocks_contains_vendor 是 Shopify 2.0 的过滤器,可自己换成任意条件。

二、写一个通用 Section:sections/vue-counter.liquid

<div class="vue-counter-section" data-vue-counter>
  <h1>{{ section.settings.heading }}</h1>
  <p>Counter 1: {{ count }}</p>
  <p>Counter 2: {{ count2 }}</p>
  <button @click="count++">+ Counter 1</button>
  <button @click="count2++">+ Counter 2</button>
</div>

<script>
  {% comment %} 把 Liquid 输出变成 JS 变量,避免全局污染 {% endcomment %}
  (function(){
    const mountEl = document.currentScript.previousElementSibling; // 上面的 div
    const appName   = 'vueCounterApp_{{ section.id }}';            // 唯一实例名

    {% comment %} 等 Vue 全局对象就绪再初始化 {% endcomment %}
    function init(){
      if (typeof Vue === 'undefined') { setTimeout(init, 50); return; }

      const { ref, createApp } = Vue;
      createApp({
        setup(){
          const count  = ref(0);
          const count2 = ref(0);
          return { count, count2 };
        }
      }).mount(mountEl);
    }
    init();
  })();
</script>

{% schema %}
{
  "name": "Vue Counter",
  "settings": [
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Counter Block"
    }
  ],
  "presets": [{ "name": "Vue Counter" }]
}
{% endschema %}

三、同一个页面拖 N 个「Vue Counter」Section

  • 每个 Section 输出 独立 DOM + 独立脚本
  • 由于 section.id 不同,变量名、挂载点互不影响;
  • Vue 全局库只加载 一次
  • 即使后续用「主题编辑器」再拖一个进来,也能立刻工作(document.currentScript 永远指向当前脚本块)。

四、如果「多个不同 Section」都要用 Vue

  1. 统一在 theme.liquid 里加一次 <script src="vue.global.prod.js" defer>
  2. 每个 Section 照抄上面「自闭环」模板即可;
  3. 想再省 2 KB,可把 createApp 逻辑抽成 全局函数
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js" defer></script>
<script>
  window.mountVueCounter = function(el){
    const { ref, createApp } = Vue;
    createApp({
      setup(){ const count=ref(0), count2=ref(0); return {count,count2}; }
    }).mount(el);
  };
</script>

然后在每个 Section 里只写:

<div class="vue-counter" data-vue-counter></div>
<script>
  (function(){
    const el = document.currentScript.previousElementSibling;
    function run(){ 
      if(typeof Vue==='undefined'){setTimeout(run,50);return;}
      window.mountVueCounter(el);
    }
    run();
  })();
</script>

五、小结

目标Shopify Section 内的正确姿势
只加载一次 Vuetheme.liquid<script src="vue.global.prod.js" defer>
不重复下载浏览器缓存 + 全局变量
每个 Section 独立section.id 做命名空间,自闭环脚本
可重复拖放document.currentScript 保证永远拿到当前块
不依赖打包器直接用 IIFE 版本,不写 type="module"

按上面模板,无论多少个 Section、多少个实例,都能做到「零重复下载、零全局污染、零冲突」。

感觉很棒,欢迎点赞 OR 打赏~
0
分享到:

评论 (0)

取消

请先登录后再进行评论或留言