首页
留言
友情链接
标签页
Search
1
那些顶级不落俗套的“美好祝福”
2,076 阅读
2
中国历史朝代顺序图
1,394 阅读
3
如何使用JavaScript获取和设置CSS root变量值
1,390 阅读
4
春和 《江海共余生》
1,009 阅读
5
唐诗三百首1-5
789 阅读
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
python
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
今日话题
登录
/
注册
Search
标签搜索
一年级语文
sunshine
累计撰写
176
篇文章
累计收到
15
条评论
首页
栏目
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
python
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
今日话题
页面
留言
友情链接
标签页
搜索到
9
篇与
的结果
2025-10-28
在shopify站点上,每个section里,代码复用实例,该怎么优化?
在 Shopify 里,一个 .liquid Section 就是一块「彼此独立、可重复、可排序」的积木。 核心限制是:每个 Section 的代码最终会被 碎片式地 拼到同一个页面上;你 不能保证 两个 Section 谁在前谁在后,也 不能保证 只出现一次;Shopify 没有「公共 JS 打包器」——不能 在 Section 里直接写 import 然后让主题统一去 type="module" 合并;浏览器仍然 重复下载 同一个 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.js 是 IIFE 版本,会把 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统一在 theme.liquid 里加一次 <script src="vue.global.prod.js" defer>;每个 Section 照抄上面「自闭环」模板即可;想再省 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 内的正确姿势只加载一次 Vue在 theme.liquid 用 <script src="vue.global.prod.js" defer>不重复下载浏览器缓存 + 全局变量每个 Section 独立用 section.id 做命名空间,自闭环脚本可重复拖放document.currentScript 保证永远拿到当前块不依赖打包器直接用 IIFE 版本,不写 type="module"按上面模板,无论多少个 Section、多少个实例,都能做到「零重复下载、零全局污染、零冲突」。
2025年10月28日
31 阅读
0 评论
0 点赞
2024-08-15
shopify recently viewed products
// Save product ID to localStorage, for use in the 'Recently viewed products' section. {%- if request.page_type == 'product' %} try { const items = JSON.parse(localStorage.getItem('cc-recently-viewed') || '[]'); // If product ID is not already in the recently viewed list, add it to the beginning. if (!items.includes({{ product.id | json }})) { items.unshift({{ product.id | json }}); } // Set recently viewed list and limit to 12 products. localStorage.setItem('cc-recently-viewed', JSON.stringify(items.slice(0, 12))); } catch (e) {} {%- endif %}
2024年08月15日
201 阅读
0 评论
0 点赞
2023-08-21
Shopify metafields json 使用方法
定义一个json格式的属性,假设定义成:product.metafields.custom.clothes在产品中设定的值为:{ "color":"red", "size":"M", "weight":"0.2kg" }在Liquid页面中使用方法:<div>color: {{ product.metafields.custom.clothes.value.color }}</div> <div>size: {{ product.metafields.custom.clother.value.size }} </div>
2023年08月21日
338 阅读
0 评论
2 点赞
2023-07-26
javascript 复制粘贴
<script> function sun_copy() { var coupon_code_dom = document.getElementById("coupon-code") var show_copy = document.getElementById("sunshine-copy") var coupon_code = coupon_code_dom.innerText var inp = document.createElement("input") document.body.appendChild(inp) inp.value = coupon_code inp.select() document.execCommand("copy", false) inp.remove() show_copy.innerText = 'Copied' } </script>
2023年07月26日
297 阅读
0 评论
0 点赞
2023-07-18
shopify 增加youtube视频和选项卡
引入相关资源<link rel="stylesheet" href="https://unpkg.com/element-ui@2.15.13/lib/theme-chalk/index.css"> <script src="https://cdn.shopify.com/s/files/1/0607/1861/2695/files/vue.min.js"></script> <script src="https://cdn.shopifycdn.net/s/files/1/0136/3119/3188/files/elementui-index.js"></script>sun-tab-video-css style liquid<style> * { margin: 0; padding: 0; box-sizing: border-box; } [v-cloak] { display: none; } @media (min-width: 1200px) { #shopify-section-header-08 .container, #shopify-section-navigation-08 .container { width: 1400px; } } .sun-video { width: 80%; margin: 50px auto; } .sun-video .video-group { display: flex; justify-content: space-between; margin: 10px 0; flex-wrap: wrap; } .sun-video .video-item { width: calc(100% / 3 - 10px); margin-top: 20px; } .sun-video .video-group:after { content: ""; display: block; width: calc(100% / 3 - 10px); height: 0; } .sun-video .video-title { display: -webkit-box; font-size: 20px; font-weight: bold; margin: 30px 0; text-align: center; min-height: 50px; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; } .sun-video .video-content { width: 100%; text-align: center; } .sun-video .video-content:hover .play-button { background: #f00; } .sun-video .youtube { background-color: #000; margin-bottom: 30px; position: relative; padding-top: 56.25%; overflow: hidden; cursor: pointer; } .sun-video .youtube img { width: 100%; top: 0; left: 0; opacity: 0.8; } .sun-video .youtube img[data-class='default'] { top: -40px; } .sun-video .youtube .play-button { width: 90px; height: 60px; background-color: #000; box-shadow: 0 0 30px rgba(0, 0, 0, 0.6); z-index: 1; opacity: 0.8; border-radius: 6px; } .sun-video .youtube .play-button:before { display:block; content: ""; border-style: solid; border-width: 15px 0 15px 26.0px; border-color: transparent transparent transparent #fff; } .sun-video .youtube img, .sun-video .youtube .play-button { cursor: pointer; } .sun-video .youtube img, .sun-video .youtube iframe, .sun-video .youtube .play-button, .sun-video .youtube .play-button:before { position: absolute; } .sun-video .youtube .play-button, .sun-video .youtube .play-button:before { top: 50%; left: 50%; transform: translate3d(-50%, -50%, 0); display:block; } .sun-video .youtube iframe { height: 100%; width: 100%; top: 0; left: 0; } .sun-video .main-container-img img { width: 100%; } @media (max-width: 1000px) { .sun-video { width: 95%; } .sun-video .video-item { width: 100%; margin: 10px auto; } } @media (min-width: 1600px) { } </style> <style> .el-tabs__nav { width: 100%; } .el-tabs__item { padding: 0; width: calc(100% / {{ section.settings.tab_count | default: 2 }}); text-align: center; /*border-left: 1px solid #ccc;*/ /*border-top: 1px solid #ccc;*/ /*border-right: 1px solid #ccc;*/ /*border-bottom: 0;*/ } .el-tabs__item.is-active { color: #e71c20; } .el-tabs__active-bar { background-color: #e71c20; /*bottom: auto;*/ } .el-tabs__item:hover { color: #e71c20; } .el-tabs--card > .el-tabs__header .el-tabs__item.is-active { border-top: 2px solid #e71c20; } </style> <div class="sun-video" id="sun-video-app" v-cloak> <el-tabs id="sun-video-tab-content" v-model="activeName" @tab-click="handleClick" type="card"> </el-tabs> </div>html section {% if customer.id or true %} {% if section.settings.render_first %} {% render 'sun-tab-video-css' %} {% endif %} {% if section.settings.tab_title == blank %} <style> .el-tabs--card>.el-tabs__header{display:none;} </style> {% endif %} <div id="{{ section.id }}" style="display:none;"> {% if section.settings.tab_title %} <el-tab-pane label="{{ section.settings.tab_title }}" name="{% if section.settings.render_first %}first{% else %} {{ section.id }}{% endif %}"> {% endif %} <div class="video-group"> {% for block in section.blocks %} <div class="video-item"> <p class="video-title">{{ block.settings.title }}</p> <div class="video-content"> <div class="youtube" data-embed="{{ block.settings.embed_id }}" data-max="{{ block.settings.max }}"> <div class="play-button"></div> </div> </div> </div> {% endfor %} </div> {% if section.settings.tab_title %} </el-tab-pane> {% endif %} </div> <script> window.sunshine.tab_html = $('#{{ section.id }}').html(); $("#sun-video-tab-content").append(window.sunshine.tab_html) </script> {% if section.settings.render_last %} {% render 'sun-tab-video-js' %} {% endif %} {% endif %} {% schema %} { "name": "Sun Tab Video", "settings": [ { "type":"checkbox", "label":"Render First", "id":"render_first", "default": false }, { "type":"checkbox", "label":"Render Last", "id":"render_last", "default": false }, { "type":"number", "label":"Tab Count", "id":"tab_count" }, { "type":"text", "label":"Tab Title", "id":"tab_title" } ], "blocks":[ { "type":"text", "name":"Tab Item", "settings": [ { "type":"text", "id":"title", "label":"Item Title" }, { "type":"text", "id":"embed_id", "label":"Youtube Embed Id" }, { "type":"checkbox", "id":"max", "label":"Thumb Image Max?", "default":true } ] } ], "presets":[ { "name":"Sun Tab Video" } ] } {% endschema %}sun-tab-video-js <script> new Vue({ el: "#sun-video-app", delimiters: ['${', '}'], data: function () { return { activeName: 'first' } }, methods: { handleChange(val) { // console.log(val); }, handleClick(tab, event) { // console.log(tab, event); }, btn_submit() { // console.log('submit') } }, created() { }, computed: {} }) </script> <script> var youtube = document.querySelectorAll(".youtube"); // loop for (var i = 0; i < youtube.length; i++) { var source = ''; var img_class = ''; // thumbnail image source. if (youtube[i].dataset.max == 'true') { source = "https://img.youtube.com/vi/" + youtube[i].dataset.embed + "/maxresdefault.jpg"; img_class = 'max'; } else { source = "https://img.youtube.com/vi/" + youtube[i].dataset.embed + "/0.jpg"; img_class = 'default'; } var image = new Image(); image.src = source; image.setAttribute('data-class', img_class); image.addEventListener("load", function () { youtube[i].appendChild(image); }(i)); youtube[i].addEventListener("click", function () { var iframe = document.createElement("iframe"); iframe.setAttribute("frameborder", "0"); iframe.setAttribute("allowfullscreen", ""); iframe.setAttribute("src", "https://www.youtube.com/embed/" + this.dataset.embed + "?rel=0&autoplay=1&showinfo=1"); this.innerHTML = ""; this.appendChild(iframe); }); } </script>
2023年07月18日
238 阅读
0 评论
2 点赞
2023-07-11
Shopify delivery date
Shopify delivery date<div class="sun-delivery"></div> <script> $(function () { const minDays = parseInt({{ block.settings.min_date | default: 0}}); const maxDays = parseInt({{ block.settings.max_date | default: 0 }}); const customText = '{{block.settings.custom_content}}'; const minDate = new Date(Date.now() + (minDays * 86400000)); const maxDate = new Date(Date.now() + (maxDays * 86400000)); const formatDate = (minDate.getFullYear() == maxDate.getFullYear() && minDate.getFullYear() == new Date().getFullYear()) ? new Intl.DateTimeFormat('en', {month: 'short', day: '2-digit'}) : new Intl.DateTimeFormat('en', {month: 'short', day: '2-digit', year: 'numeric'}); const tipText = customText.replace(/\{min_date\}/g, '<b>' + formatDate.format(minDate) + '</b>') .replace(/\{max_date\}/g, '<b>' + formatDate.format(maxDate) + '</b>'); $('.sun-delivery').html(tipText) }) </script>
2023年07月11日
268 阅读
0 评论
0 点赞
2023-04-20
Shopify Liquid使用汇总
产品价格显示save了多少,代码如下:{% if product.compare_at_price > product.price %} You save {{ product.compare_at_price | minus: product.price | times: 100.0 | divided_by: product.compare_at_price | money_without_currency | times: 100 | remove: '.0'}}% {% endif %}获取单个产品的信息:标题,原价,现价,链接,图片等信息{{ product.title }} {{ product.compare_at_price }} {{ product.price }} {{ product.url }} {{ product.images.first | img_url: 'master' }}获取单个分类,多个分类的产品信息{%- for product in collections[section.settings.product_list_collection].products -%} <!--这里是单个产品 --> {% endif %}add to cart链接<a href="/cart/add?id={{ product.selected_or_first_available_variant.id }}&quantity=1">add to cart</a>
2023年04月20日
255 阅读
0 评论
2 点赞
2023-01-14
Shopify Blog Listing Code
<aside> {%- if section.settings.blog_show_tags -%} <ul> <li> {%- for tag in blog.all_tags -%} <a href="{{ blog.url }}/tagged/{{ tag | handle }}">{{ tag }}</a>{% unless forloop.last %}, {% endunless %} {%- endfor -%} </li> </ul> {%- endif -%} </aside> {% schema %} { "name": "Blog posts", "settings": [ { "type": "checkbox", "id": "blog_show_tags", "label": "Show tags", "default": true } ] } {% endschema %}
2023年01月14日
103 阅读
0 评论
1 点赞
2022-10-27
Shopify,Shoplaza平台全局参数一览
shopifypurchase事件中:订单号:{{ order.order_number }} 订单金额:{{ total_price | times: 0.01 }} 运费:{{ shipping_price | times: 0.01 }} 币种:{{ order.currency }}Shoplazapurchase事件中订单号:{{ checkout.order_id }} 金额:{{ checkout.total_price }} 订单总金额(check.total_price) = 商品优惠后的总价(check.line_items_subtotal_price) + 税费(check.tax_price) + 物流费(check.shipping_price)计算销售额Shopify: sale = subtotal_price + total_shipping Shoplaza: sale = sub_total - total_discount + total_tax + total_shipping获取collection产品信息shopify: {% assign collection = section.settings.collection %} {% assign products = collections[collection].products %} {% for product in products %} {% assign price = product.price | money_with_currency %} {% assign retailPrice = product.compare_at_price | money_with_symbol %} {% assign productImage = product.images[0].src | img_url: '640x' %} {% assign url = product.url %} {% endfor %}shoplaza: {% assign collection = section.settings.collection %} {% assign products = collections[collection.id].products %} {% for product in products %} {% assign price = product.price | money_with_symbol %} {% assign retailPrice = product.compare_at_price | money_with_symbol %} {% assign productImage = product.image.src | img_url: '640x' %} {% assign url = product.url %} {% endfor %} {% assign single_product = section.settings.select_product %} {% assign one_product = all_products[single_product.id] %} shoplaza获取单个产品自定义属性(json格式时)和其他产品参数信息 {% assign product = all_products[section.settings.product.id] %} {% assign icons = product.metafields.sunshine.show_case.value.icons %}save off (%){% if select_product.compare_at_price > select_product.price %} {% assign saveOFF = select_product.compare_at_price | minus: select_product.price | times: 100 | divided_by: select_product.compare_at_price | round %} {% endif %}
2022年10月27日
244 阅读
0 评论
4 点赞