2.1 主题定制组件搬迁至 3.0 主题

1. 安装开发工具

1.1. 安装 SHOPLINE CLI

在 Windows、macOS 上安装 SHOPLINE CLI,这里提供了 npm 和 yarn 两种安装方法进行安装。

npm install --global @shoplineos/cli

或者

yarn global add @shoplineos/cli

cli使用教程点击:backhand_index_pointing_right:使用教程查看。

1.2. 安装3.0开发插件

VS Code 开发者插件,点击:backhand_index_pointing_right:扩展安装包进行下载安装。详细使用教程点击:backhand_index_pointing_right:使用教程查看。

用户排查主题代码语法中的语法错误。

2. 获取3.0主题代码

2.1. 添加3.0主题

如想在已发布的3.0主题进行开发,可忽略此添加3.0主题步骤。
点击【在线商店】>【店铺设计】>【主题商城】。


选择需要的3.0主题。

添加对应的3.0主题。

添加完成效果:

2.2. 拉取3.0主题代码进行开发

桌面创建空白文件夹

进入该文件夹的终端输入以下命令,登录店铺。

sl login --store 店铺handle.myshopline.com

以下是通过此命令,登录到店铺handle为zhenghaonan的示例:


输入完命令并回车,浏览器自动跳转至登录页面。

登录完成。

再输入以下命令,显示店铺所有的主题代码。

sl theme pull

以下是通过此命令,显示zhenghaonan店铺所有的主题代码的示例:
如您想对已发布的主题进行开发,选择带[live]符号的主题。


按键盘上下健,选择对应的3.0主题,再按回车键即可拉取。

再输入以下命令,进行实时预览开发。

sl theme serve

以下是通过此命令返回的信息:

  1. 本地预览链接:http://127.0.0.1:8282 此链接指向你的开发主题的链接。此 URL 可以热重新加载对本地文件的更改,或在文件更改时刷新整个页面,允许你使用店铺的数据实时预览更改。无法使用此链接预览结账页。
  2. SHOPLINE 后台中主题编辑器的链接:Shopline Editor
  3. 你可以与其他开发人员共享的预览链接:https://zhenghaonan.myshopline.com/?preview=1&themeId=690978b35ad5f3fc52297292&dev_mode=1。

3. 抽离 2.1 主题中定制的组件代码

3.1. 找到 2.1 定制组件代码(含 html / css / js 文件)

3.2. 按 2.1 组件结构拉取代码至文件夹

2.1主题组件代码结构:

assets 包含主题中使用的所有资产,包括 Image、CSS 和 JavaScript 文件。
locales 包含主题的 [locale 文件](https://developer.shopline.com/zh-hans-cn/docs/themes-2-0/architecture/locales/overview),用于提供翻译后的内容。
sections 包含一个主题的所有 [section](https://developer.shopline.com/zh-hans-cn/docs/themes-2-0/architecture/sections/overview) 文件。
snippets 包含 Handlebars HTML 文件,用于托管较小的可重用代码片段。

按照 2.1 组件代码结构,将 2.1 定制组件代码移至对应 2.1 目录。

4. 2.1 定制组件转移至 3.0 主题

2.1 定制组件转为 3.0 组件代码结构

3.0主题组件代码结构:

blocks          		# 可复用的区块				  针对 3.0 组件特性拆分出的公共 block 目录
components      	# 公共代码片段				  与 2.1 主题目录 snippets 作用相同
i18n            		# 多语言配置文件               	  与 2.1 主题目录 locales 作用相同
public          		# 静态资源(图片/CSS/JS/字体)与 2.1 主题目录 assets 作用相同
sections        		# 页面组件与组件集			  与 2.1 主题目录 sections 作用相同

:warning:注意:
1、3.0 代码结构中每个 section 为一个文件夹。
2、不再支持 2.1 组件 block 在 section 中直接创建的形式。
3、3.0 主题若 html 有对应 css / js ,均放入同命名文件夹。
按照 3.0 组件代码结构,将 2.1 定制组件代码移至对应 3.0 目录。


按照3.0组件目录搬迁至3.0主题代码中相应的位置。

5. 按照 3.0 语法结构修改组件代码

5.1. 修改引用 CSS / JS 语法及路径

原 2.1 定制组件  case-studies.html 引入示例如下:
{{snippet "stylesheet" href=(asset_url "swiper@11/swiper-bundle.min.css")}}
<script src="{{asset_url 'swiper@11/swiper-bundle.min.js'}}" defer></script>
{{snippet "stylesheet" href=(asset_url " case-studies/ case-studies.css")}}
<script src="{{asset_url ' case-studies/ case-studies.js'}}" defer></script>
{{snippet " section-style" section=section}}
{{snippet " section-common" section=section}}

3.0 组件引用 CSS 格式如下:

{{#component “stylesheet” src="CSS路径 " | asset_url() /}}

3.0 组件引用 JS 格式如下:

{{#component “script” src="JS路径 " | asset_url() /}}

3.0组件引用公共模块格式如下:
{{#component "公共模块的路径 " /}}

按照以上 3.0 组件引用代码格式及 3.0 组件文件目录
将原 2.1 定制组件转化成 3.0  case-studies.html 示例如下:
{{#component "stylesheet" src="component/swiper@11/swiper-bundle.min.css" | asset_url() /}}
{{#component "script" src="component/swiper@11/swiper-bundle.min.js" | asset_url() /}}
{{#component "stylesheet" src="./ case-studies.css" | asset_url() /}}
{{#component "script" src="./ case-studies.js" | asset_url() /}}
{{#component " section-style" /}}
{{#component " section-common/ section-common" /}}

5.2. 修改 2.1 组件代码适配 3.0 主题

5.2.1. 修改 settings 配置项

原 2.1 组件  case-studies.html settings 配置项示例如下:
{{#schema}}
{
  "name": "Case Studies",
  "settings": [
    {
      "id": "common_title",
      "type": "richtext",
      "label": "标题",
      "default": "Section Title"
    },
    {
      "id": "common_content",
      "type": "richtext",
      "label": "内容",
      "default": "Section Content"
    },
    {
      "type": "product_picker",
      "id": "common_button_add_cart_product",
      "label": "商品选择器"
    },
    {
      "type": "color",
      "id": "bg_color",
      "label": "背景颜色",
      "default": "#FFFFFF"
    },
  ],

3.0 控件类型 :backhand_index_pointing_right: 3.0 编辑器控件类型库

3.0 组件图标 :backhand_index_pointing_right: 3.0 编辑器组件图标库

3.0 用于修改变量和对象的输出Filter :backhand_index_pointing_right: 3.0 Sline filter 同 2.1 主题 :backhand_index_pointing_right: Handlebars helpers

3.0 用于定义指示模板执行操作的逻辑Tag :backhand_index_pointing_right: 3.0 Sline tag

2.1 语法与 3.0 语法差异 :backhand_index_pointing_right: Handlebars & Sline 语法差异对比
:warning: 注意:

  1. 发现当前 2.1 组件控件未在 3.0 主题显示时,可在 3.0 编辑器控件类型库 文档中查找最新格式/使用 其他控件代替。
    场景如:商品选择器:2.1 中使用 product_picker,在 3.0 中需使用 product,否则无效 。

  2. 3.0 组件/主题代码中如有语法错误,会导致整块内容不显示。
    场景如:当 section 代码中有语法时,该 section 在主题编辑器组件库中不显示。

  3. 如 2.1 代码中使用 {{#comment}} 注释 {{/comment}} 进行注释,需更换为 {{!-- 注释 --}} 。

  4. 2.1 Handlebars helpers 需替换成 3.0 Sline filter / 3.0 Sline tag 。
    场景如:2.1 主题对一个控件值使用 helpers default
    {{default section.settings.bg_color ‘#000’}}
    在 3.0 主题需更改写法
    {{ section.settings.bg_color.hex | default(“#000”) }}

按照以上 3.0 注意事项及 3.0 相关文档修改  case-studies.html 代码示例如下:
{{#schema}}
{
  "name": "Case Studies",
  "settings": [
    {
      "id": "common_title",
      "type": "richtext",
      "label": "标题",
      "default": "Section Title"
    },
    {
      "id": "common_content",
      "type": "richtext",
      "label": "内容",
      "default": "Section Content"
    },
    {
      "type": "product",      将原 2.1 的控件类型product_picker 转化为 3.0 的product
      "id": "common_button_add_cart_product",
      "label": "商品选择器"
    },
    {
      "type": "color",
      "id": "bg_color",
      "label": "背景颜色",
      "default": "#FFFFFF"
    },
  ],

5.2.2. 修改 block 的创建方式

原 2.1 组件  case-studies.html 添加 blocks 示例如下:
{{#schema}}
{
  "name": "Case Studies",
  "settings": [
	...省略上方相关代码
  ],
"blocks": [
    {
      "icon": "normal",
      "type": "card",
      "name": "卡片",
      "settings": [
        {
          "id": "link",
          "type": "url",
          "label": "跳转链接"
        },
        {
          "id": "media_image",
          "type": "image_picker",
          "label": "图片"
        },
        {
          "id": "media_local_video",
          "type": "video",
          "label": "本地视频"
        },
        {
          "id": "media_external_youtube_video",
          "type": "video_url",
          "format": "video",
          "label": "youtube视频链接",
          "placeholder": "https://www.youtube.com/watch?v=V7BEzkRBp_g",
          "info": "支持youtube"
        },
        {
          "id": "media_external_video",
          "type": "text",
          "label": "外部视频链接",
          "placeholder": "https://cdn4.fireworktv.com/medias/2025/1/14/1736847602-iqkgazld/watermarked/720/smart_pc.mp4",
          "info": "支持firework"
        }
      ]
    }
  ],

根据 3.0 组件特性,目前 3.0 组件不支持区块 block 直接创建 , block 需拆分成私有区块 / 公有区块。

公有区块:可以被任意组件或区块引用的区块,创建目录如下:

3.0主题文件夹
    ├─ blocks

私有区块:只能被对应组件及对应组件下的私有区块引用,创建目录如下:

3.0主题文件夹

├─ sections

├─ 对应组件文件夹

├─ blocks

根据 2.1 定制组件的需求,在对应文件夹下创建 3.0 对应区块文件。

假设 block 名为:product-card 
对应 product-card.html 文件代码如下:
{{#schema}}
{
  "icon": "normal",
  "type": "card",
  "name": "卡片",
  "tag": "",  	tag--外层元素代码:不写tag字段默认div包裹,tag传空值则去除默认父级元素,
                                                     传xxx,则父级元素为<xxx></xxx>
   "settings": [
        {
          "id": "link",
          "type": "url",
          "label": "跳转链接"
        },
        {
          "id": "media_image",
          "type": "image",     将原 2.1 的控件类型 image_picker 转化为 3.0 的image
          "label": "图片"
        },
        {
          "id": "media_local_video",
          "type": "video",
          "label": "本地视频"
        },
        {
          "id": "media_external_youtube_video",
          "type": "external_video",     将原 2.1 的控件类型 video_url 转化为 3.0 的 external_video
          "format": "video",
          "label": "youtube视频链接",
          "placeholder": "https://www.youtube.com/watch?v=V7BEzkRBp_g",
          "info": "支持youtube"
        },
        {
          "id": "media_external_video",
          "type": "text",
          "label": "外部视频链接",
          "placeholder": "https://cdn4.fireworktv.com/medias/2025/1/14/1736847602-iqkgazld/watermarked/720/smart_pc.mp4",
          "info": "支持firework"
        }
      ],
"block":[]
}
{{/schema}}

修改对应Section的引用方式:

按照创建的区块,修改 case-studies.html 添加 block 的代码如下:
{{#schema}}
{
  "name": "Case Studies",
  "settings": [
	...省略上方相关代码
  ],
 "blocks":[
{
      "type": "$product-card",  如果区块为私有区块,则添加 $ 符号,若是公有区块,则去除 $ 。
      "limit": 1			     添加该区块的最大数量
}
]
}
{{/schema}}

5.2.3. 修改代码中引用 block 的方式

3.0 渲染当前 Section / Block 子级 Blocks 的方式:

  1. 仅支持渲染当前 section / block 下的动态 blocks 。
{{#content "blocks" /}}
  1. 渲染当前 section / block 下的动态 block ,支持往子级 block 传对象值,作用域内会下发 forblock 对象,支持做一些特殊逻辑处理。
{{#blocks}}
	{{#block /}}
{{/blocks}}

3.0 Section / Block 传对象值给子级 Blocks 并渲染的方式:

  1. 传 Section 的控件配置项/特定的值给子级 Blocks 并渲染的格式:
    {{#blocks}}
    {{#block 自定义传值名称=section.settings.控件id 自定义传值名称=自定义值 /}}
    {{/blocks}}
Section 渲染子级 Blocks 时传 title 的配置值及自定义参数 isBigBox 的示例如下:

{{#blocks}}

{{#block title=section.settings.title isBigBox=true /}}

{{/blocks}}
  1. 传 Block 的控件配置项/特定的值给子级 Blocks 并渲染的格式:
    {{#blocks}}
    {{#block 自定义传值名称=block.settings.控件id 自定义传值名称=自定义值 /}}
    {{/blocks}}
Block 渲染子级 Blocks 时传 richtext 的配置值及自定义参数 isSmallBox 的示例如下:

{{#blocks}}

{{#block text=section.settings.richtext isSmallBox=true /}}

{{/blocks}}
  1. 传 Section / Block 中定义的变量给子级 Blocks 并渲染的格式:
    {{#var 变量名 /}} 定义变量
    {{#set 变量名 = 变量值 /}} 赋值变量
    {{#blocks}}
    {{#block 自定义传值名称=变量名 /}} 使用变量
    {{/blocks}}
Section / Block 渲染子级 Blocks 时传定义的变量示例如下:
{{#var isBox /}} 					
{{#set isBox = true /}}	 				
{{#blocks}}
{{#block isBigBox=isBox /}}
{{/blocks}}
  1. Section / Block 渲染特定的子级 block 并传参数,可结合 forblock.type 判断子级 block 的类型进行操作。
    格式:
    {{#blocks}}
    {{#if forblock.type == “子级 block 的类型” }}
    {{#block 自定义传值名称=变量名 /}}
    {{/if}}
    {{/blocks}}
Section / Block 渲染特定的子级 block 并传参数示例如下: 				
{{#blocks}}
	{{#if forblock.type == "$product-cart" }} 	  	    如果区块为私有区块,则添加 $ 符号,
    		{{#block text=section.settings.richtext  /}}      若是公有区块,则去除 $ 。
  	{{/if}}
{{/blocks}}

3.0 子级 Block 引用 Section / Block 传参的方式:

格式:

{{ props.自定义传值名称 }}

子级 Block 引用 Section 传参 title 及 isBigBox 的示例如下:

{{ props.title }}

{{ props.isBigBox }}

3.0 Section/Block 拿取子级blocks 的值的方式:

格式:

{{#blocks}}

{{ forblock.settings.子级 block 配置项的控件 Id /}}

{{/blocks}}

Section / Block 显示子级 blocks title 配置项 title 的值示例如下:
{{#blocks}}
{{ forblock.settings.title /}}
{{/blocks}}

获取特定的子级 block 配置参数,可结合 forblock.type 判断子级 block 的类型进行操作。
格式:
{{#var 变量名 /}}
{{#blocks}}
{{#if forblock.type == “子级 block 的类型” }}
{{#set 变量名 = forblock.settings.子级 block 配置项的控件 Id /}}
{{/if}}
{{/blocks}}

Section / Block 获取特定的子级 Block 配置 title 参数示例如下:
{{#var enable_info_layer /}}
{{#blocks}}
  {{#if forblock.type == "product-card/info" }}
    {{#set enable_info_layer = forblock.settings.title /}}
  {{/if}}
{{/blocks}}
原 2.1 组件  case-studies.html 引用 blocks 示例如下:
<div class="case-studies-swiper">
      <div class="swiper-wrapper">
{{#for section.blocks as |block|}}
        <div class="swiper-slide  case-studies-card {{#if (or block.settings.media_image block.settings.media_local_video block.settings.media_external_youtube_video block.settings.media_external_video)}} case-studies-card-with-media{{/if}}">
            <div class="case-studies-card-content-title">
              {{{block.settings.title}}}
            </div>
              <div class="case-studies-card-content-avatar-image">
                {{snippet "image" data=block.settings.avatar_image}}
              </div>
              <div class="case-studies-card-content-avatar-content">
                <div class="case-studies-card-content-avatar-content-title">
                  {{{block.settings.avatar_title}}}
                </div>
                <div class="case-studies-card-content-avatar-content-text">
                  {{{block.settings.avatar_content}}}
                </div>
              </div>
          </div>
{{/for }}
</div>
</div>

根据上方 Section / Block 与子级 Block 的相关交互方式,以 {{#for section.blocks as |block|}} 为分界线,按照该组件的需求,将 {{#for}} 里面的代码分别添加至创建的对应子级 block,并添加对应的 block 配置项代码。

如:将 .case-studies-card-content-title 拆分成一个私有/公有区块,在对应目前下添加文件 title.html,并粘贴代码及添加对应的配置项。

 假设 block 名为:product-card-content
对应 product-card-content.html 文件代码如下:
<div class="swiper-slide  case-studies-card {{#if block.settings.media_image || block.settings.media_local_video || block.settings.media_external_youtube_video || block.settings.media_external_video}} case-studies-card-with-media{{/if}}">
⚠️:需关注当前 helper 是否适配 3.0,如 3.0 不再支持 or 。 
            <div class="case-studies-card-content-title">
              {{{block.settings.title}}}
            </div>
              <div class="case-studies-card-content-avatar-image">
                {{snippet "image" data=block.settings.avatar_image}}
              </div>
              <div class="case-studies-card-content-avatar-content">
                <div class="case-studies-card-content-avatar-content-title">
                  {{{block.settings.avatar_title}}}
          </div>
         <div class="case-studies-card-content-avatar-content-text">
                  {{{block.settings.avatar_content}}}
         </div>
    </div>
</div>
{{#schema}}
{
  "icon": "normal",
  "type": "card",
  "name": "标题",
  "tag": "",  	tag--外层元素代码:不写tag字段默认div包裹,tag传空值则去除默认父级元素,
                                                     传xxx,则父级元素为<xxx></xxx>
   "settings": [
        {
          "id": "title",
          "type": "richtext",
          "label": "标题"
        },
...省略相关代码,⚠️:添加时需关注配置项是否适配 3.0 。
      ],
"block":[]
}
{{/schema}}

添加完,按照 block 显示需求,修改对应的 section 文件。

3.0 组件 case-studies.html 引用 blocks 示例如下:
<div class="case-studies-swiper">
      <div class="swiper-wrapper">
{{#blocks }}		⚠️:需关注当前 helper 是否适配 3.0,如 3.0 渲染 block 不支持使用 for 。 
{{#if forblock.type == "$product-card-content" }}  如区块为私有区块,则添加 $ 符号
{{#block /}}
{{/if }}
{{/blocks }}
</div>
</div>
{{#schema}}
{
  "name": "Case Studies",
  "settings": [
	...省略上方相关代码
  ],
 "blocks":[
{
      "type": "$product-card-content",  如区块为私有区块,则添加 $ 符号,公有区块则去除。
      "limit": 1			     添加该区块的最大数量
},
...省略上方相关代码
]
}
{{/schema}}

5.2.4. 修改 presets 预设代码

假设 2.1 定制组件在 presets 的代码如下:
"presets": [
    {
      "category_index": 1,
      "category": "t:sections.rich-text.presets.presets__0.category",
      "name": "t:sections.rich-text.presets.presets__0.name",
      "settings": {
        "desktop_content_position": "center",
        "color_scheme": "none",
        "normal_width": true,
        "show_decoration": false,
        "padding_top": 60,
        "padding_bottom": 60
      },
      "blocks": [
        {
          "type": "heading",
          "settings": {
            "heading": "heading",
            "heading_size": "title3"
          }
        },
        {
          "type": "text",
          "settings": {
            "text": "<p>A sentence or two introducing your brand, what you sell, and what makes your brand compelling to customers.</p>"
          }
        }
      ]
    }
  ]

:warning:3.0 组件 presets 下的 blocks 支持嵌套,整个组件的层级最多为五层。

3.0 组件 presets 下的 blocks 嵌套代码示例如下:
"presets": [
    {
        "name": "视频推荐商品",  			 	    一层
        "settings":{
...省略其他配置代码
        },
        "blocks": [
            {
                "type": "$float-video"                             二层
            },
            {
                "type": "$collection",                              二层
                "blocks": [
                    {
                        "type": "$product-card",		   三层
                        "blocks": [
                            {
                                "type": "$image"			   四层
                		"blocks": [
                    			{
"type": "$title"	       五层
} 
                               ]
                            },
                            {
                                "type": "$quick_add"		   四层
                            }
                        ]       
                    }
                ]   
            }
        ]
    }
]

按照目前 3.0 组件 blocks 的类型,进行修改。

对应的 3.0 组件 presets 代码示例如下:
"presets": [
    {
      "category_index": 1,
      "category": "t:sections.rich-text.presets.presets__0.category",
      "name": "t:sections.rich-text.presets.presets__0.name",
      "settings": {
	...省略其他配置代码
      },
      "blocks": [
        {
          "type": "$heading", 			如区块为私有区块,则添加 $ 符号,公有区块则去除。
          "settings": {
            "heading": "heading",
            "heading_size": "title3"
          },
          "blocks":[					按照组件的新显示需求,将区块进行嵌套
{
"type":"text",
 "settings": {
            "text": "<p>A sentence or two introducing your brand, what you sell, and what makes your brand compelling to customers.</p>"
          }
}
          ]
        }
      ]
    }
  ]

5.2.5. 将 2.1 组件 locales 多语言文件代码搬迁至 3.0 i18n

假设原定制组件在 locales 目录下 zh-hans-cn.schema 的语料如下:
{
  "sections": {
...省略其他语料代码
"main-article": {
      	"name": "博客文章",
      "blocks": {
        "select": {
          "name": "配图",
          "settings": {
            "image_height": {
              "label": "封面图高度",
              "options__0": {
                "label": "适应图片"
              },
              "options__1": {
                "label": "小"
              },
              "options__2": {
                "label": "中"
              },
              "options__3": {
                "label": "大"
              }
            }
          }
        },
        "title": {
          "name": "标题",
          "settings": {
            "blog_show_date": {
              "label": "显示日期"
            },
            "blog_show_author": {
              "label": "显示作者"
            }
          }
        },
        "share": {
          "name": "分享"
        },
        "content": {
          "name": "内容"
        }
      }
    }
},
"settings_schema":{
...省略其他语料的代码
}
}

可直接将对应 json 复制粘贴至 3.0 i18n 目录下的 zh-hans-cn.schema

对应的 3.0  zh-hans-cn.schema 引用 blocks 示例如下:
{
  "sections": {
...省略其他语料代码
"main-article": {
      	"name": "博客文章",
      "blocks": {
        "select": {
          "name": "配图",
          "settings": {
            "image_height": {
              "label": "封面图高度",
              "options__0": {
                "label": "适应图片"
              },
              "options__1": {
                "label": "小"
              },
              "options__2": {
                "label": "中"
              },
              "options__3": {
                "label": "大"
              }
            }
          }
        },
        "title": {
          "name": "标题",
          "settings": {
            "blog_show_date": {
              "label": "显示日期"
            },
            "blog_show_author": {
              "label": "显示作者"
            }
          }
        },
        "share": {
          "name": "分享"
        },
        "content": {
          "name": "内容"
        }
      }
    }
},
"settings_schema":{
...省略其他语料的代码
},
"blocks":{
...省略其他语料的代码
}
}

在对应位置,继续使用引用代码即可。

按照以上操作,即可实现将 2.1 主题定制组件搬迁至 3.0 主题。