


让 SHOPLINE 购物车更友好地显示定制数据
让 SHOPLINE 购物车更友好地显示定制数据
2025年9月18日
先看效果

让我们开始吧!
登录你的 SHOPLINE 后台,进入 在线商店 > 店铺设置 页面。

这里我们用 SHOPLINE 的 Modern 主题(2.1)为例并拷贝,点击 “更多” 按钮,进入 “编辑代码” 页面。

选择 “Snippets” 文件并点击 “新建 snippet” 按钮。

创建一个名为 customeow-data.html 的文件。

复制下面全部代码并粘贴到 customeow-data.html 的文件中。
{{!-- Renders CustoMeow Custom Data for Shopline Theme 2.0 Accepts: - properties: {Array} Cart item properties - title: {String} Custom data title (optional) - enable_dark: {Boolean} Website dark mode, default is false (optional) - text_color: {String} text color, hex or rgba, default is oklch(37.3% .034 259.733), enable_dark text color is white. (optional) - preview_font_size: {Number} Preview text font size (optional), 12~16, default is 12 - preview_image_width: {Number} Preview image width (optional), default is 60 - preview_image_radius: {Number} Preview image border radius (optional), default is 6 - enable_modal: {Boolean} Show image modal when true - modal_background_color: '' {String} Image modal background color, hex or rgba, default is black (optional) - cart_item_id: {String} Cart item id (optional) - cart_item_image_classname: {String} Preview first image cover thumbnail (optional) Usage: {{> customeow-data properties=item.properties title='Your personalization' preview_font_size=12 preview_image_width=60 preview_image_radius=6 enable_modal=true}} --}} {{assign "show_title" true}} {{#unless title}} {{assign "show_title" false}} {{/unless}} {{assign "is_dark" false}} {{#if enable_dark}} {{assign "is_dark" true}} {{/if}} {{assign "label_color" "oklch(37.3% .034 259.733)"}} {{#if text_color}} {{assign "label_color" text_color}} {{/if}} {{#if preview_font_size}} {{#if preview_font_size < 12 or preview_font_size > 16}} {{assign "preview_font_size" 12}} {{/if}} {{else}} {{assign "preview_font_size" 12}} {{/if}} {{#unless preview_image_width}} {{assign "preview_image_width" 60}} {{/unless}} {{assign "preview_modal_radius" 12}} {{assign "preview_modal_inner_radius" 11}} {{#if preview_image_radius}} {{assign "preview_modal_radius" (times preview_image_radius 2)}} {{assign "preview_modal_inner_radius" (minus preview_modal_radius 1)}} {{/if}} {{assign "enable_image_modal" true}} {{#unless enable_modal}} {{assign "enable_image_modal" false}} {{/unless}} {{#unless modal_background_color}} {{assign modal_background_color 'black'}} {{/unless}} {{assign "item_id" ''}} {{#if cart_item_id}} {{assign "item_id" cart_item_id}} {{/if}} {{assign "cart_item_class" ''}} {{#if cart_item_image_classname}} {{assign "cart_item_class" cart_item_image_classname}} {{/if}} {{assign "property_texts" ''}} {{assign "property_orginal_images" ''}} {{#for properties as |property|}} {{#if property.name == "preview.texts"}} {{assign "property_texts" (split property.value ',')}} {{else if property.name == "preview.effects" or property.name == "preview.images"}} {{#if (size property_orginal_images) > 0}} {{assign "property_orginal_images" (append property_orginal_images (append ',' property.value))}} {{else}} {{assign "property_orginal_images" property.value}} {{/if}} {{/if}} {{/for}} {{assign "property_images" (split property_orginal_images ',')}} {{#if enable_image_modal}} <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script> {{/if}} <style> .cm-customization { margin-top: 20px; } .cm-customization-title { font-size: 14px; font-weight: 500; color: {{#if is_dark}}white{{else}}{{label_color}}{{/if}}; } .cm-customization-container { padding: 4px 0 8px; display: none; } .cm-customization-container.active { display: block; } .cm-customization-texts { display: flex; gap: 8px; flex-wrap: wrap; } .cm-customization-texts-tag { padding: 2px 4px; border-radius: 4px; background-color: {{#if is_dark}}rgba(255,255,255,0.06){{else}}rgba(0,0,0,0.06){{/if}}; color: {{#if is_dark}}white{{else}}{{label_color}}{{/if}}; font-size: {{preview_font_size}}px; } .cm-customization-images { margin-top: 8px; display: flex; gap: 8px; flex-wrap: wrap; } .cm-customization-images-thumbnail { width: {{preview_image_width}}px; border-radius: {{preview_image_radius}}px; overflow: hidden; position: relative; aspect-ratio: 1 / 1; } .cm-customization-images-thumbnail.cursor-pointer { cursor: pointer; } .cm-customization-images-thumbnail:before { content: ''; position: absolute; left: 0; top: 0; width: 100%; height: 100%; border: 1px solid {{#if is_dark}}rgba(255,255,255,0.2){{else}}rgba(0,0,0,0.2){{/if}}; border-radius: {{preview_image_radius}}px; } .cm-customization-images-thumbnail img { width: 100%; height: 100%; object-fit: cover; } .cm-customization-images-thumbnail-mask { width: 100%; height: 100%; position: absolute; left: 0; top: 0; background-color: rgba(0,0,0,0.4); display: flex; justify-content: center; align-items: center; opacity: 0; transition: all cubic-bezier(0.33, 1, 0.68, 1) 200ms; } .cm-customization-images-thumbnail:hover .cm-customization-images-thumbnail-mask { opacity: 1; } .cm-customization-images-thumbnail-svg { width: 20px; height: 20px; } .cm-customization-transition { transition: all 200ms cubic-bezier(0.33, 1, 0.68, 1); } .cm-customization-bg-from { opacity: 0; } .cm-customization-bg-to { opacity: 1; } .cm-customization-modal-from { opacity: 0; transform: scale(0.94); } .cm-customization-modal-to { opacity: 1; transform: scale(1); } .cm-customization-close-from { opacity: 0; transform: translateY(10px); } .cm-customization-close-to { opacity: 1; transform: translateY(0); } .cm-customization-modal { width: 100%; height: 100%; position: fixed; left: 0; top: 0; z-index: 99999999; display: flex; justify-content: center; align-items: center; flex-direction: column; } .cm-customization-modal-bg { width: 100%; height: 100%; position: absolute; background-color: rgba(0,0,0,0.8); z-index: 0; } .cm-customization-splide { width: 80%; aspect-ratio: 1 / 1; background-color: {{modal_background_color}}; position: relative; z-index: 1; border-radius: {{preview_modal_radius}}px; overflow: hidden; } .cm-customization-splide:before { content: ''; position: absolute; left: 1px; right: 1px; top: 1px; bottom: 1px; border: 1px solid rgba(255,255,255,0.16); border-radius: {{preview_modal_inner_radius}}px; z-index: 10; pointer-events: none; } .cm-customization-splide .cm-customization-splide-frame, .cm-customization-splide img { width: 100%; height: 100%; object-fit: contain; } .cm-customization-splide .cm-customization-splide-frame { aspect-ratio: 1 / 1; position: relative; } .cm-customization-splide .cm-customization-splide-button { display: none; } .cm-customization-splide:hover .cm-customization-splide-button { display: block; } .cm-customization-splide-button { width: 36px; height: 36px; background-color: white; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); border-radius: 100px; position: absolute; top: 50%; transform: translateY(-50%); cursor: pointer; } .cm-customization-splide-button span { width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; } .cm-customization-splide-button span svg { width: 16px; height: 16px; fill: oklch(44.6% 0.03 256.802); } .cm-customization-splide-left { left: 12px; } .cm-customization-splide-right { right: 12px; } .cm-customization-modal-close { width: 36px; height: 36px; border: 2px solid white; border-radius: 100%; position: relative; z-index: 5; display: flex; justify-content: center; align-items: center; margin-top: 20px; cursor: pointer; } .cm-customization-modal-close svg { width: 20px; height: 20px; } @media (width >= 640px) { .cm-customization-splide { width: 480px; } } {{#if item_id and cart_item_class}} #{{item_id}} .{{cart_item_class}} { position: relative; } #{{item_id}} .{{cart_item_class}}:before { content: ''; width: 100%; height: 100%; background-image: url({{first (split property_orginal_images ',')}}); background-position: center top; background-size: contain; background-color: white; background-repeat: no-repeat; position: absolute; left: 0; top: 0; } {{/if}} </style> <div class="cm-customization"> {{#if show_title}} <div class="cm-customization-title">{{ title }}</div> {{/if}} <div class="cm-customization-container" :class="init ? 'active' : ''" x-data="{ init: false, openModal: false, previewIndex: 0, imageArray: [], currentImageUrl: '', showSlideLeftButton: false, showSlideRightButton: false }" x-init="init = true"> {{!-- texts --}} {{#if (size property_texts) > 0 }} <div class="cm-customization-texts"> {{#for property_texts as |item| }} <span class="cm-customization-texts-tag">{{ item }}</span> {{/for}} </div> {{/if}} {{!-- preview thumbnail --}} {{#if (size property_images) > 0}} <div class="cm-customization-images"> {{#for property_images as |item|}} <div class="cm-customization-images-thumbnail {{#if enable_image_modal}}cursor-pointer{{/if}}" x-data="{ index: {{ forloop.index0 }}, propertyImages: '{{ property_orginal_images }}' }" @click=" previewIndex = index imageArray = propertyImages.split(',') if (imageArray.length > 1) { if (index > 0 && index < imageArray.length - 1) { showSlideLeftButton = true showSlideRightButton = true } else if (index === 0) { showSlideLeftButton = false showSlideRightButton = true } else if (index === imageArray.length - 1) { showSlideLeftButton = true showSlideRightButton = false } } currentImageUrl = imageArray[index] openModal = true "> {{#if enable_image_modal}} <div class="cm-customization-images-thumbnail-mask"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="white" class="cm-customization-images-thumbnail-svg"> <path d="M9 6a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0v-1.5h-1.5a.75.75 0 0 1 0-1.5h1.5v-1.5A.75.75 0 0 1 9 6Z" /> <path fill-rule="evenodd" d="M2 9a7 7 0 1 1 12.452 4.391l3.328 3.329a.75.75 0 1 1-1.06 1.06l-3.329-3.328A7 7 0 0 1 2 9Zm7-5.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11Z" clip-rule="evenodd" /> </svg> </div> {{/if}} <img width="120" height="120" src="{{ item }}?x-oss-process=image/resize,s_{{times preview_image_width 2}}" /> </div> {{/for}} </div> {{/if}} {{!-- preview image modal --}} {{#if enable_image_modal}} <div class="cm-customization-modal" x-show="openModal"> <div class="cm-customization-splide" role="group" aria-label="{{ title }}" x-show="openModal" x-transition:enter="cm-customization-transition" x-transition:enter-start="cm-customization-modal-from" x-transition:enter-end="cm-customization-modal-to" x-transition:leave="cm-customization-transition" x-transition:leave-start="cm-customization-modal-to" x-transition:leave-end="cm-customization-modal-from"> <div class="cm-customization-splide-frame"> <img width="400" height="400" :src="currentImageUrl + '?x-oss-process=image/resize,l_960'"> <div x-show="showSlideLeftButton" class="cm-customization-splide-button cm-customization-splide-left" @click=" previewIndex -= 1 currentImageUrl = imageArray[previewIndex] if (imageArray.length > 1) { if (previewIndex > 0 && previewIndex < imageArray.length - 1) { showSlideLeftButton = true showSlideRightButton = true } else if (previewIndex === 0) { showSlideLeftButton = false showSlideRightButton = true } else if (previewIndex === imageArray.length - 1) { showSlideLeftButton = true showSlideRightButton = false } } "> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"> <path fill-rule="evenodd" d="M14 8a.75.75 0 0 1-.75.75H4.56l3.22 3.22a.75.75 0 1 1-1.06 1.06l-4.5-4.5a.75.75 0 0 1 0-1.06l4.5-4.5a.75.75 0 0 1 1.06 1.06L4.56 7.25h8.69A.75.75 0 0 1 14 8Z" clip-rule="evenodd" /> </svg> </span> </div> <div x-show="showSlideRightButton" class="cm-customization-splide-button cm-customization-splide-right" @click=" previewIndex += 1 currentImageUrl = imageArray[previewIndex] if (imageArray.length > 1) { if (previewIndex > 0 && previewIndex < imageArray.length - 1) { showSlideLeftButton = true showSlideRightButton = true } else if (previewIndex === 0) { showSlideLeftButton = false showSlideRightButton = true } else if (previewIndex === imageArray.length - 1) { showSlideLeftButton = true showSlideRightButton = false } } "> <span> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4"> <path fill-rule="evenodd" d="M2 8a.75.75 0 0 1 .75-.75h8.69L8.22 4.03a.75.75 0 0 1 1.06-1.06l4.5 4.5a.75.75 0 0 1 0 1.06l-4.5 4.5a.75.75 0 0 1-1.06-1.06l3.22-3.22H2.75A.75.75 0 0 1 2 8Z" clip-rule="evenodd" /> </svg> </span> </div> </div> </div> <div class="cm-customization-modal-close" x-show="openModal" x-transition:enter="cm-customization-transition" x-transition:enter-start="cm-customization-close-from" x-transition:enter-end="cm-customization-close-to" x-transition:leave="cm-customization-transition" x-transition:leave-start="cm-customization-close-to" x-transition:leave-end="cm-customization-close-from" @click=" openModal = false "> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="white"> <path d="M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z" /> </svg> </div> <div class="cm-customization-modal-bg" x-show="openModal" x-transition:enter="cm-customization-transition" x-transition:enter-start="cm-customization-bg-from" x-transition:enter-end="cm-customization-bg-to" x-transition:leave="cm-customization-transition" x-transition:leave-start="cm-customization-bg-to" x-transition:leave-end="cm-customization-bg-from" @click=" openModal = false "><span></span></div> </div> {{/if}} </div> </div>
你也可以下载 customeow-data.html 文件。
保存代码文件(快捷键:保存文件)

找到
snippets/cart-item.html文件。本教程基于 SHOPLINE 2.0 主题版本,如果你的主题版本与教程不匹配,你可以尝试搜索
item.properties as |property|来找到代码位置。

按下 Command/Ctrl + F 来打开搜索窗口,搜索 item.properties as |property| 代码。(快捷键:搜索)


选择红色区域按 Command/Ctrl + / 注释代码。(快捷键:注释代码)

复制下列代码并粘贴到 snippets/cart-item.html 文件中。
{{!-- CustoMeow Custom Data --}} {{snippet 'customeow-data' properties=item.properties title='Your personalization' enable_dark=false text_color='#000000' preview_font_size=12 preview_image_width=60 preview_image_radius=6 enable_modal=true modal_background_color='#000000' cart_item_id='' cart_item_image_classname='' }}
粘贴到所注释的代码下面。

保存代码文件。
(快捷键:保存文件)

那么,我们测试一下!
推出编辑器,返回店铺设计页面,点击“设计”按钮。

保持 CustoMeow 应用开启状态,不要忘记保存!

现在预览你的网站。

找到你的定制化产品,定制后加入购物车,进入购物车查看是否有效。

Cool! 购物车现在已经能够更友好的显示定制数据啦!
如果你的购物车是抽屉样式,推荐设置 enable_modal=false 避免抽屉宽度小于查看图片宽度影响用户体验。
高级设置
你可以更改设置来满足你的个性化。
{{!-- CustoMeow Custom Data --}} {{snippet 'customeow-data' properties=item.properties title='Your personalization' enable_dark=false text_color='#000000' preview_font_size=12 preview_image_width=60 preview_image_radius=6 enable_modal=true modal_background_color='#000000' cart_item_id='' cart_item_image_classname='' }}
接下来,让我们逐一了解每一个设置。
properties(必填项):接收购物车的定制化参数。
properties=item.properties
title(可选项):显示定制化模块的标题。
title='Your personalization'
推荐标题使用获取国际化文案的方式。
{{assign "customeow_title" (t "cart.properie.title")}} {{snippet 'customeow-data' properties=item.properties title=customeow_title enable_modal=true }}
enable_dark(可选项):如果设置为 true,text color 将强制为白色,图片风格也会更改为暗黑模式, 默认是 false。
enable_dark=false
text_color(可选项):文字颜色, 支持 hex 或 rgba 格式, 默认是 'oklch(37.3% .034 259.733)'。
text_color='#000000'
preview_font_size(可选项):预览内容的文字尺寸,12~16px 之间, 默认是 12px。
preview_font_size=12
preview_image_width(可选项):预览图片的缩略图宽度,默认是 60px。
preview_image_width=60
preview_image_radius(可选项):预览图片的缩略图圆角,默认是 6px。
preview_image_radius=6
enable_modal(必填项):开启点击预览图片缩略图,将弹出查看大图窗口,默认是 true。
enable_modal=true
modal_background_color(可选项):设置查看大图窗口的背景色。
modal_background_color='#000000'
将预览图片覆盖到产品图片上
cart_item_id 和 cart_item_image_classname 参数必须同时设置才能有效。
cart_item_id(可选项):
(1)购物车商品唯一 ID,通常使用商品排序作为 ID,您可以在
snippets/cart-item.html文件中找到购物车商品 ID。(2)如果没有 ID,你也可以手动添加
item.index来实现唯一 ID。CartItem-{{plus item.index 1}}
cart_item_image_classname(可选项):购物车商品项中图片父级的 classname。

这里是最终代码。
{{!-- add item id --}} {{assign "cart_item_index" (plus item.index 1)}} {{assign "cart_item_id" (append 'CartItem-' cart_item_index)}} {{!-- CustoMeow Custom Data --}} {{snippet 'customeow-data' properties=item.properties title='Your personalization' enable_dark=false text_color='#000000' preview_font_size=12 preview_image_width=60 preview_image_radius=6 enable_modal=true modal_background_color='#000000' cart_item_id=cart_item_id cart_item_image_classname='meow-cart-item-image' }}
保存代码,回到购物车,我们去看看实际效果!
