Visual Studio Code 插件安装 - Shopify Liquid
Visual Studio Code 插件安装 - Liquid
网络资料:
一、环境搭建
安装参考:www.jianshu.com/p/3d0ec5b6a…
1、ruby 安装
https://www.ruby-lang.org/zh_cn/
# 下载地址
https://rubyinstaller.cn/
注:下载完成后,一直下一步就好,忽略掉过程,完成完成后 fish 会打开 cmd。
记得按回车,安装成功后 cmd 自动关闭。
2、shopify-cli 下载(gem 后面放弃掉)
# 这个下载的,必然是 2.X.X,可惜这样的是错的
gem install shopify-cli
# 使用上面这种方式安装后升级
shopify upgrade
使用 npm 下载(推荐)
注:也可看 shopify 官网的升级流程。
# 用它下载的是 3.X.x 版本
npm install -g @shopify/cli @shopify/theme
3、shopify 版本查看
shopify version
4、登出(拉取项目时的异常处理)
注:如果报上面的错,就代表你需要登出一下,才可以拉取项目。
shopify auth logout
二、Shopify 开发
官网地址:shopify.dev/docs
1、Shopify cli 的使用
1) 登录
必须要在网页中进行当前项目的的登陆哦,负责会出现问题的。
2)拉取项目
shopify theme pull --store 你的项目名.myshopify.com
# 以下面的地址为例子,你登陆完项目后,需要定位到主页
# 然后去查看项目名
# https://admin.shopify.com/store/quickstart-c566b596 这个里面的项目名就是 quickstart-c566b596
# 下载的链接就为:
# shopify theme pull --store quickstart-c566b596.myshopify.com
这个时候会在出现一次登陆,记得登陆之前 ① 的账户。
3)运行
shopify theme dev
4) 推送项目 ⚠️
注:应该做一个 git 脚本化,每次 cr 到 main 分支后,自动执行 shopify theme push --store quickstart-c566b596.myshopify.com 去实现,拒绝人工搬运。
shopify theme push --store 你的项目名.myshopify.com
# 以下面的地址为例子,你登陆完项目后,需要定位到主页
# 然后去查看项目名
# https://admin.shopify.com/store/quickstart-c566b596 这个里面的项目名就是 quickstart-c566b596
# 下载的链接就为:
# shopify theme push --store quickstart-c566b596.myshopify.com
2、目录结构
3、修改项目
三、liquid 的语法基础
注:vsc 插件下载 Shopify Liquid。
1、schema
注:一个基础的 liquid 文件。
<style>
</style>
<div class="">
<div>
{{ section.settings.collection_id }}
</div>
</div>
<script>
</script>
{% schema %}
{
"name": "测试",
"class": "",
"settings": [
],
"presets": [
{
"name": "测试"
}
]
}
{% endschema %}
1)settings 的使用
<style>
.box_list {
display: flex;
width: 100%;
background-color: rosybrown;
}
.box_item {
/* 使用 schema 的变量 */
width: {{ section.settings.width }}px;
height: {{ section.settings.height }}px;
border: 1px solid red;
background-color: aqua;
}
</style>
<div class="box_list">
<div class="box_item">
<button>
{{ section.settings.height }}
</button>
</div>
<div class="box_item">121</div>
<div class="box_item">131</div>
</div>
{% schema %}
{
"name": "Box List",
"settings": [
{
// 作为模板时的输入框类型
"type": "text",
// 作为获取的 key
"id": "height",
// 输入框的文案
"label": "每个 item 的高度",
// 输入框的默认值
"default": "100px"
},
{
"type": "text",
"id": "width",
"label": "每个 item 的宽度",
"default": "100px"
}
],
"presets": [
{
"name": "Box List"
}
]
}
{% endschema %}
settings
是一个 json 数组,json 对象的参数如下:
属性 | 参数 | 描述 |
---|---|---|
type | number 数字 string 字符串 text 文本 textarea 文本域 range checkbox radio select 下拉框 image_picker 图片选择 url 链接(内部跳转的时候使用) collection 只能使用 产品 —> 收藏里面的内容 inline_richtext richtext color 颜色 | 控制 |
id | 自己定义的字符串 | 1、自己定义的字符串; 2、取值的时候使用 section.settings.你刚才定义的 id 字符串; 3、理解成获取变量的 key |
label | 自己起的面板文案 | 定义面板的的文案 |
default | 定义的默认值 | |
info | 面板的提示信息 |
注:
① collection 案例
<div>
{{ section.settings.collection_id }}
{{ collections[section.settings.collection_id].url }}
{{ collections[section.settings.collection_id].title }}
{{ collections[section.settings.collection_id].image }}
{{
collections[section.settings.collection_id].image
| image_url: width: 500
| image_tag: loading: 'lazy', widths: '165, 360, 535, 750, 1070, 1500'
}}
</div>
{% schema %}
{
"name": "test",
"settings": [
{
"type": "collection",
"id": "collection_id",
"label": "collection 使用"
}
],
"presets": [
{
"name": "测试"
}
]
}
{% endschema %}
只能展示 这个下面的内容。
2)blocks
注:blocks 是一个 json 数组
属性 | 参数 | 描述 |
---|---|---|
type | 一个自己定义的 string | |
name | 作为编辑器中的名称使用 | |
limit | 当面这个控制面板,在 添加块 中,能使用的次数(默认是不限制的) | |
settings | 一个 json 数组,参数同 schema 中 settings 的使用 |
初步案例:
注:
① blocks 为一个对象的数组。
<div>
{% comment %} 读取 blocks 中的参数 {% endcomment %}
{%- for block in section.blocks -%}
<div class="{{ block.settings.font_size }}">{{ block.settings.richtext }}</div>
{%- endfor %}
</div>
{% schema %}
{
"name": "blocks 测试",
"tag": "section",
"class": "section",
"blocks": [
{
"type": "test",
"name": "添加 inline_richtext",
"settings": [
{
"type": "inline_richtext",
"id": "richtext",
"default": "文案",
"label": "标题文案"
},
{
"type": "select",
"id": "font_size",
"options": [
{
"value": "h0",
// FOXME 反人类,html 店铺是从 h1 开始的
"label": "H0"
},
{
"value": "h1",
"label": "H1"
},
{
"value": "h2",
"label": "H2"
},
{
"value": "h3",
"label": "H3"
},
{
"value": "h4",
"label": "H4"
},
{
"value": "h5",
"label": "H5"
}
],
"default": "h0",
"label": "标题大小"
}
]
}
],
"presets": [
{
"name": "blocks 测试"
}
]
}
{% endschema %}
② blocks 为多个个对象的数组
<div>
{% comment %} 读取 blocks 中的参数 {% endcomment %}
{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when 'test1' -%}
<div class="{{ block.settings.font_size }}">{{ block.settings.richtext }}</div>
{%- when 'test2' -%}
{% comment %} 一定要有图片不为 blank 的判断 {% endcomment %}
{%- if block.settings.image != blank -%}
{%- assign widths = '165, 360, 535, 750, 1070, 1500' -%}
{{ block.settings.image | image_url: width: 500 | image_tag: loading: 'lazy', widths: widths }}
{%- endif -%}
{%- endcase -%}
{%- endfor -%}
</div>
{% schema %}
{
"name": "blocks 测试",
"tag": "section",
"class": "section",
"blocks": [
/*
特殊 "type": "@app" 是添加一个应用
使用的时候是:
{% for block in section.blocks %}
{% case block.type %}
{% when '@app' %}
{% render block %}
{% endcase %}
{% endfor %}
*/
// {
// "name": "",
// "type": "@app"
// },
{
"type": "test1",
"name": "添加 inline_richtext",
"limit": 2,
"settings": [
{
"type": "inline_richtext",
"id": "richtext",
"default": "文案",
"label": "标题文案"
},
{
"type": "select",
"id": "font_size",
"options": [
{
"value": "h0",
// FOXME 反人类,html 店铺是从 h1 开始的
"label": "H0"
},
{
"value": "h1",
"label": "H1"
},
{
"value": "h2",
"label": "H2"
},
{
"value": "h3",
"label": "H3"
},
{
"value": "h4",
"label": "H4"
},
{
"value": "h5",
"label": "H5"
}
],
"default": "h0",
"label": "标题大小"
}
]
},
{
"type": "test2",
"name": "图片",
"settings": [
{
"type": "image_picker",
"id": "image",
// 这个一般就不要默认地址了
// "default": "",
"info": "图片",
"label": "选择图片"
}
]
}
],
"presets": [
{
"name": "blocks 测试"
}
]
}
{% endschema %}
3)在Dom 元素中的使用 schema
2、css
注:css 的引入,只能在 sections、layout 中使用。
1)局部引入(直接引入 css 文件)
{{- 'test.css' | asset_url | stylesheet_tag: preload: true -}}
2)分区中设置 css (也就是局部变量的设置)
/*
#shopify-section- 是所有分区的统一命名,是不会改变的
{{ section.id }} 是系统自己生成
如果你要局部修改,就只能这样修改,负责你就是全局修改的样式
*/
#shopify-section-{{ section.id }} .section {
padding-block-start: 30px;
padding-block-end: 30px;
}
3)icon-font 的引入
{% comment %} 直接在 layout ——> theme.liquid 引入就好 {% endcomment %}
{{- 'iconfont.css' | asset_url | stylesheet_tag: preload: true -}}
3、图片展示
schema 选择图片
{{
section.settings.image
| image_url: width: 500
| image_tag: loading: 'lazy',
widths: '165, 360, 535, 750, 1070, 1500'
}}
4、render ✅
注:render 渲染的 liquid 文件,只能在 snippets
文件里,并且 render 渲染的文件中不支持 schema
。
1)传参
5、style ⁉️
{%- style -%}
{%- endstyle -%}
基本上等于
所以使用的时候,你就使用 style
标签就好,没必要使用 {%- style -%}。
6、过滤器
所有文件的引入,都要使用 {{ '文件名.css/js' | asset_url }}
7、引入 vue
注:不推荐,会感觉四不像,如果真的使用 推荐方法一,文件比较集中(而且 liquid 中用 vue 就很变态)。
1)引入 vue 的方法一
① 在 layout ——> theme.liquid 中
{% comment %} 记得放在 head 里 {% endcomment %}
<script src="https://unpkg.com/vue@next"></script>
② 使用 sections ——> test.liquid
注:raw 文档
<div id="vue-app">
{% comment %} 这块也可以加一个 div 去渲染 data 中的数据,写法如下,不推荐
<div v-html="name"></div>
{% endcomment %}
{% assign variable = '测试 assign 变量在 Vue 中的使用' %}
{% raw %}
{{ name }}
{% endraw %}
<button @Click="handleClick">修改 assign 的变量 </button>
</div>
<script>
const el = {
data() {
return {
name: '{{ variable }}'
}
},
methods: {
handleClick() {
this.name = '修改'
console.log(this.name);
}
}
}
const app = Vue.createApp(el)
app.mount("#vue-app");
</script>
{% schema %}
{
"name": "测试",
"settings": [
],
"presets": [
{
"name": "测试"
}
]
}
{% endschema %}
2)引入 vue 的方法二
① 在 layout ——> theme.liquid 中
{% comment %} 记得放在 head 里 {% endcomment %}
<script src="{{ 'vue 的js 文件路径' | asset_url }}" defer></script>
② 在 layout ——> test.js.liquid 中
new Vue({
el: '#app',
data: {
name: '2222'
}
})
③ 使用 sections ——> test.liquid
<div id="app">
<div v-html="name"></div>
</div>
<script src="{{ 'test.js' | asset_url }}" defer></script>
{% schema %}
{
"name": "测试",
"settings": [
],
"presets": [
{
"name": "测试"
}
]
}
{% endschema %}
注:react 的引用同理
四、常用 liquid 语法及方法
1、上下间距调节器
<style>
.top-bottom_-margin {
height: 0;
background-color: black !important;
margin-top: {{ section.settings.top_bottom_space }}px;
}
</style>
<div class="top-bottom_-margin" style="display: block;"></div>
{% schema %}
{
"name": "上下间距调节器",
"settings":[
{
"type": "range",
"id": "top_bottom_space",
"label": "左右拖动调节间距",
"max": 100,
"min": 0,
"step": 1,
"default": 30
}
],
"presets":[
{
"name": "上下间距调节器",
"category": "Advanced"
}
]
}
{% endschema %}
2、链接
<style>
.section-more-box {
display: flex;
justify-content: center;
margin-top: 20px;
}
.section-more-box .more-link {
display: block;
border: 1px solid #000;
background: #fff;
padding: 10px 4px 8px;
text-align: center;
width: 200px;
color: #000;
font-weight: 700;
cursor: pointer;
box-sizing: border-box;
}
.section-more-box .more-link:hover {
color: #fff;
background: #000;
}
@media only screen and (max-width:767px) {
.section-more-box {
padding: 0 16px;
}
.section-more-box .more-link {
width: 100%;
}
}
</style>
<div class="section-more-box">
<div class="more-link"> {%- if section.settings.link and section.settings.text -%}{{ section.settings.text | link_to: section.settings.link }}{%- endif -%}</div>
</div>
{% schema %}
{
"name": "链接",
"settings": [
{
"type": "url",
"id": "link",
"label": "链接"
},
{
"type": "text",
"id": "text",
"label": "链接文案",
"default": "链接文案"
}
],
"presets": [
{
"name": "链接"
}
]
}
{% endschema %}
3、发送邮件
注:会让你验证,但是这个是成功的,倒霉的让我改了好久(不要在本地验证,本地他不让发邮件的)。
<style>
.box-email {
position: relative;
display: inline-block;
}
.submit {
position: absolute;
top: 0;
right: 0;
}
/* 修改 input 聚焦后的颜色 */
input:active, input:focus {
border-color: var(--colorBorder);
}
/* 修改 input 填充后颜色 */
input:-webkit-autofill {
transition: background-color 5000s ease-in-out 0s;
}
/* 修改 input 填入文字的颜色 */
input {
-webkit-text-fill-color: var(--colorBorder);
}
</style>
<div class="box-email">
{% form 'customer' %}
{{ form.errors | default_errors }}
{%- if form.posted_successfully? -%}
成功
{%- else -%}
{%- if form.errors -%}
失败
{%- endif -%}
<input type="hidden" name="contact[tags]">
<div class="email">
<input type="email" name="contact[email]">
</div>
<div class="submit">
<input type="submit" value="Send">
</div>
{%- endif -%}
{% endform %}
</div>
4、返回顶部按钮
<style>
html {
scroll-behavior: smooth;
}
.scroll-to-top-btn {
position: fixed;
right: 0.51rem;
bottom: 2.0267rem;
z-index: 2;
height: 38px;
width: 38px;
border-radius: 100%;
box-shadow: 0 0 2px rgba(0,0,0,.12);
transform: translateY(0);
background: #fff;
/* 居中 */
display: flex;
justify-content: center;
align-items: center;
/* 动画 */
opacity: 0;
transform: translateY(100px);
transition: all .5s ease;
}
.showBtn {
opacity: 1;
transform: translateY(0);
}
.scroll-to-top-btn .icon-top-arrow {
height: 28px;
width: 28px;
color: #000;
}
.scroll-to-top-btn[disabled] {
color: white !important;
background: #730000 !important;
}
</style>
<div>
{% comment %} 返回 {% endcomment %}
<button class="scroll-to-top-btn">
{% render "top-arrow.svg" %}
</button>
</div>
<script>
let scrollToTopBtn = document.querySelector(".scroll-to-top-btn");
let scrollTop = 0;
window.onscroll = function() {
scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
if(scrollTop == 0) {
scrollToTopBtn.disabled = false;
}
if (scrollTop > 100) {
scrollToTopBtn.classList.add("showBtn")
} else {
scrollToTopBtn.classList.remove("showBtn")
}
};
scrollToTopBtn.onclick = function() {
window.scrollTo(0, 0);
scrollToTopBtn.disabled = true;
};
</script>
{% schema %}
{
"name": "返回顶部",
"presets": [
{
"name": "返回顶部"
}
]
}
{% endschema %}
{% comment %} 返回 svg {% endcomment %}
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon-top-arrow" width="100%" height="00%" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#000000" d="M486.4 263.509333l-175.7184 175.7184a25.6 25.6 0 1 1-36.181333-36.215466l219.409066-219.409067a25.6 25.6 0 0 1 36.181334 0l219.4432 219.409067a25.6 25.6 0 0 1-36.215467 36.181333L537.6 263.509333v574.293334a25.6 25.6 0 1 1-51.2 0V263.509333z" /></svg>
5、表单
注:
① create_customer 创建表单时,他不支持返回成功的提示(深坑 !!!)
③ 获取请求 request (也就是当前 url 的信息)之后的状态
注:表单不是很好用。
6、调用 shopify 中定义的方法
注:类似调用购物车的弹出框。
/**
* 直接获取到 DOM 元素,然后去 click,不要尝试使用 theme.js 里面的方法哦,里面全是原型链,难以阅读,需要 大量的时间
*/
document.querySelector(".mobile-nav-trigger").click();
7、顶部 bar
注:如果你只链接收藏的话,也可以考虑 collection 属性,但是他很单一,很多是无法进行设置的,不推荐。
<style>
@media only screen and (min-width: 768px) {
#shopify-section-{{ section.id }} .tabs {
display: none;
}
}
.tabs-sticky {
/* position: fixed;
top: {{ section.settings.top_space }}vh; */
}
.tabs {
width: 100vh;
display: grid;
grid-auto-flow: column;
grid-auto-columns: 36%;
max-width: 100vw;
overflow-x: scroll;
gap: 8px;
background: #fff;
padding: 0 10px;
}
.tabs::-webkit-scrollbar {
display: none;
}
.tabs a {
display: inline-block;
padding: 8px;
box-sizing: border-box;
margin: 0;
background-color: #f5f5f5;
border-radius: 4px;
vertical-align: bottom;
display: flex;
flex-direction: row;
align-items: center;
}
.tabs a:first-child {
margin-left: 0px;
}
#shopify-section-{{ section.id }} p {
white-space: wrap;
overflow: hidden;
text-overflow: ellipsis;
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp:2;
font-size: 12px;
color: #666;
margin-top: 4px;
text-align: center;
}
#shopify-section-{{ section.id }} .image {
width: 30%;
}
[data-status="selected"] {
border:1px solid #4e4d4d;
}
/* #4e4d4d */
</style>
<div>
<div class="tabs">
{%- for block in section.blocks -%}
<a href="{{ block.settings.link }}" class="tabs-link">
{%- if block.settings.image != blank -%}
<div class="image">
{{
block.settings.image
| image_url: width: 500
| image_tag: loading: 'lazy', widths: '165, 360, 535, 750, 1070, 1500'
}}
</div>
{%- endif -%}
{%- if block.settings.text != blank -%}
<p>
{{ block.settings.text }}
</p>
{%- endif -%}
</a>
{%- endfor %}
</div>
</div>
<script>
let tabs = document.querySelector('.tabs')
window.addEventListener('scroll',function(e){
if(window.pageYOffset > tabs.offsetTop){
tabs.style.position = 'fixed'
tabs.style.top = '60px'
tabs.style.zIndex = '9'
tabs.style.paddingBottom = '10px'
}else {
tabs.style.position = 'unset'
}
})
const bottomBar = document.getElementsByClassName('tabs-link');
const url = window.location.href;
for (let index = 0; index < bottomBar.length; index++) {
if(element.href == url) {
tabs.scrollTo(element.offsetLeft, 0);
element.setAttribute('data-status', 'selected')
}else {
element.removeAttribute('data-status')
}
}
</script>
{% schema %}
{
"name": "顶部 tabs",
"class": "tabs-sticky",
"settings":[
{
"type": "range",
"id": "top_space",
"label": "距离顶部距离",
"max": 100,
"min": 0,
"step": 1,
"default": 6
}
],
"blocks": [
{
"type": "tabs",
"limit": 8,
"name": "tabs",
"settings": [
{
"type": "image_picker",
"id": "image",
"label": "tab 图片"
},
{
"type": "url",
"id": "link",
"label": "tab 链接"
},
{
"type": "text",
"id": "text",
"label": "tab 文案"
}
]
}
],
"presets": [
{
"name": "顶部 tabs"
}
]
}
{% endschema %}
8、获取产品信息
9、获取登陆信息
{% if shop.customer_accounts_enabled %}
{% if customer %}
{% comment %} 已经登陆 {% endcomment %}
<a href="{{ routes.account_url }}">账户 url</a>
{% else %}
暂无登陆
<a href="{{ routes.account_login_url }}">登陆 url</a>
{% if shop.customer_accounts_optional %}
<a href="{{ routes.account_register_url }}">创建账户 url</a>
{% endif %}
{% endif %}
{% endif %}
10、元字段
文档:
11、界面跳转
12、获取当前 liquid 文件中的部分数据
13、assign (变量)
<div id="vue-app">
{% assign variable = '测试' %}
{{ variable }}
</div>
<script>
console.log("{{ variable }}");
</script>
{% schema %}
{
"name": "测试",
"settings": [
],
"presets": [
{
"name": "测试"
}
]
}
{% endschema %}
14、capture 定义 html
<div id="vue-app">
{% capture testHtml %}
<div>渲染的时 html 标签</div>
{%- endcapture -%}
{{ testHtml }}
</div>
{% schema %}
{
"name": "测试",
"settings": [
],
"presets": [
{
"name": "测试"
}
]
}
{% endschema %}
15、for (遍历)
16、过滤器 🗑️
注:很差劲的东西,大部分前端框架已经 🚮 的玩意,liquid 反而在大量使用,体验差!!!
17、订单属性
18、图片的引入
background-image: url({{ '图片名.格式' | asset_url }});
<img src="{{ '图片名.格式' | asset_url }}" alt="播放" width="30" height="30" />
19、显示指定行数,超出显示省略号
元素选择器 {
display: -webkit-box;
overflow: hidden;
white-space: normal;
text-overflow: ellipsis;
word-wrap: break-word;
-webkit-line-clamp: 2; /* 要显示的行数,超出显示省略号 */
-webkit-box-orient: vertical;
}
20、三角
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.small-triangle {
width: 0;
height: 0;
border-left: 6px solid #ff8e59;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
}
</style>
</head>
<body>
<div class="small-triangle"></div>
</body>
</html>
21、走马灯 🪲
<style>
.revolving-door, .second-line_revolving-door {
position: relative;
width: calc(100vw - 80px);
height: 200px;
overflow: hidden;
}
.revolving-door-ul, .second-line_revolving-door-ul {
list-style: none;
position: absolute;
left:0;
top:0;
display: grid;
grid-auto-flow: column;
grid-auto-columns: 200px;
gap: 15px;
}
.revolving-door-li, .second-line_revolving-door-li img{
width:100%;
height: 100%;
border-radius: 20px;
}
.revolving-door-button {
display: flex;
justify-content: flex-end;
}
.second-line_revolving-door {
margin-top: 2.5rem;
}
.revolving-door::-webkit-scrollbar{
width:10px;
height:10px;
}
.revolving-door::-webkit-scrollbar-track{
background: rgb(239, 239, 239);
border-radius:2px;
}
.revolving-door::-webkit-scrollbar-thumb{
background: #bfbfbf;
border-radius:10px;
}
.revolving-door::-webkit-scrollbar-thumb:hover{
background: #333;
}
.revolving-door::-webkit-scrollbar-corner{
}
.second-line_revolving-door::-webkit-scrollbar{
width:10px;
height:10px;
}
.second-line_revolving-door::-webkit-scrollbar-track{
background: rgb(239, 239, 239);
border-radius:2px;
}
.second-line_revolving-door::-webkit-scrollbar-thumb{
background: #bfbfbf;
border-radius:10px;
}
.second-line_revolving-door::-webkit-scrollbar-thumb:hover{
background: #333;
}
</style>
<div style="padding: 2.5rem 40px;">
<div class="revolving-door-button">
<button class="pause">
<img src="../assets/zanting.png" alt="暂停" width="30" height="30" />
</button>
<button class="play">
<img src="../assets/bofang.png" alt="播放" width="30" height="30" />
</button>
</div>
<div class="revolving-door">
<ul class="revolving-door-ul">
{%- for block in section.blocks -%}
{% if block.type == 'first-row' %}
<li class="revolving-door-li">
{% if block.settings.image != block %}
{{
block.settings.image
| image_url: width: 500
| image_tag: loading: 'lazy',
widths: '200',
class: 'revolving-door-image'
}}
{% endif %}
{% if block.settings.video != block %}
<video
id="Mp4Video-{{ block.settings.video }}"
class="video-div"
data-type="mp4"
src="{{ block.settings.video }}"
loop muted playsinline autoplay></video>
{% endif %}
</li>
{% endif %}
{%- endfor %}
</ul>
</div>
<div class="second-line_revolving-door">
<ul class="second-line_revolving-door-ul">
{%- for block in section.blocks -%}
{% if block.type == 'second-line' %}
<li class="second-line_revolving-door-li ">
{% if block.settings.second-line_image != block %}
{{
block.settings.second-line_image
| image_url: width: 500
| image_tag: loading: 'lazy',
widths: '200',
class: 'second-line_revolving-door-image'
}}
{% endif %}
</li>
{% endif %}
{%- endfor %}
</ul>
</div>
</div>
<script>
// 暂停
const pause = document.querySelector('.pause');
const play = document.querySelector('.play');
// 第一行
let left = 0;
let timer = null;
let secondLineLeft = -10;
let secondLineTimer = null;
setTimeout(() => {
const revolvingDoorUl = document.querySelector('.revolving-door-ul');
const revolvingDoorLi = document.getElementsByClassName('revolving-door-li');
const revolvingImage = document.getElementsByClassName('revolving-door-image')[0];
const revolvingDoor = document.querySelector('.revolving-door');
// 获取图片的宽高,赋值给 revolving-door-ul
revolvingDoor.style.height = revolvingImage.offsetHeight + 'px';
revolvingDoor.style.gridAutoColumns = revolvingImage.offsetWidth + 'px';
if(revolvingDoorLi.length < 6) {
clearInterval(timer)
}
revolvingDoorUl.innerHTML += revolvingDoorUl.innerHTML;
function firstRow() {
timer = setInterval(function () {
left -= 1;
revolvingDoorUl.style.width = revolvingDoorLi.length * revolvingDoorLi[0].offsetWidth+'px';
if(left < -revolvingDoorUl.offsetWidth/2) {
left = 0;
}
revolvingDoorUl.style.left=left+'px'
}, 10);
}
firstRow();
// 第二行
const secondLineRevolvingDoorUl = document.querySelector('.second-line_revolving-door-ul');
const secondLineRevolvingDoorLi = document.getElementsByClassName('second-line_revolving-door-li');
const secondLineRevolvingImage = document.getElementsByClassName('second-line_revolving-door-image')[0];
const secondLineRevolvingDoor = document.querySelector('.second-line_revolving-door');
// 获取图片的宽高,赋值给 revolving-door-ul
secondLineRevolvingDoor.style.height = secondLineRevolvingImage.offsetHeight + 'px';
secondLineRevolvingDoor.style.gridAutoColumns = secondLineRevolvingImage.offsetWidth + 'px';
secondLineRevolvingDoorUl.innerHTML += secondLineRevolvingDoorUl.innerHTML;
function secondLine() {
secondLineTimer = setInterval(function () {
secondLineLeft -= 1;
secondLineRevolvingDoorUl.style.width = secondLineRevolvingDoorLi.length * secondLineRevolvingDoorLi[0].offsetWidth+'px';
if(secondLineLeft < -secondLineRevolvingDoorUl.offsetWidth/2) {
secondLineLeft = 0;
}
secondLineRevolvingDoorUl.style.left=secondLineLeft+'px'
}, 10);
}
if(secondLineRevolvingDoorUl.length <= 6) {
console.log("我走了");
clearInterval(secondLineTimer)
}
secondLine();
pause.onclick = function() {
clearInterval(timer)
clearInterval(secondLineTimer)
pause.style.display = 'none';
play.style.display = 'block';
revolvingDoor.style.overflowX = 'scroll';
secondLineRevolvingDoor.style.overflowX = 'scroll';
}
play.onclick = function() {
firstRow();
secondLine();
pause.style.display = 'block';
play.style.display = 'none';
}
// 额外的事件处理
revolvingDoor.addEventListener("drag", (params) => {
clearInterval(timer);
revolvingDoor.style.overflowX = 'scroll';
})
secondLineRevolvingDoor.addEventListener("drag", (params) => {
clearInterval(secondLineTimer);
secondLineRevolvingDoor.style.overflowX = 'scroll';
})
function scroll() {
}
}, 500)
play.style.display = 'none';
</script>
{% schema %}
{
"name": "跑马灯",
"blocks": [
{
"type": "first-row",
"name": "第一行",
"settings": [
{
"type": "image_picker",
"id": "image",
"label": "图片(每行至少六个图片 或 视频)"
},
{
"id": "video",
"type": "video",
"label": "视频"
}
]
},
{
"type": "second-line",
"name": "第二行",
"settings": [
{
"type": "image_picker",
"id": "second-line_image",
"label": "图片(每行至少六个图片 或 视频)"
},
{
"id": "video",
"type": "video",
"label": "视频"
}
]
}
],
"presets": [
{
"name": "走马灯"
}
]
}
{% endschema %}
22、swiper 的引入
<link rel="stylesheet" href="https://unpkg.com/swiper@8/swiper-bundle.min.css">
<style>
.swiper {
overflow: hidden;
width: 100%;
height: {{ section.settings.desktop_image_height }}px;
}
@media screen and (max-width: 699px) {
.banner-gailery {
width: 100%;
height: {{ section.settings.mobile_image_height }}px;
}
}
.swiper-container {
height: 100%;
position: relative;
}
.swiper-button-next:after, .swiper-button-prev:after {
font-size: 16px;
color: #000;
font-weight: 900;
}
.swiper-slide {
width: {{ section.settings.image_width }}%;
}
.swiper-pagination-bullet {
background-color: {{ section.settings.paginator_color }};
height: 10px;
width: 10px;
opacity: 1;
}
.swiper-pagination-bullet-active {
border: 2px solid {{ section.settings.paginator_color }};
background-color: transparent;
}
</style>
<div class="banner-gailery">
<div class="swiper-container">
<div class="swiper-wrapper">
<!--
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
-->
<!-- 添加更多的轮播项 -->
{%- for block in section.blocks -%}
{%- if block.settings.image -%}
{% capture img %}
<div class="swiper-slide">
{{
block.settings.image
| image_url: width: 500
| image_tag: loading: 'lazy', widths: '165, 360, 535, 750, 1070, 1500'
}}
</div>
{%- endcapture -%}
{{ img }}
{%- endif -%}
{%- if block.settings.image and block.settings.link_url -%}
<a href="{{ block.settings.link_url }}" class="swiper-slide">
{{ img }}
</a>
{%- endif -%}
{%- endfor %}
</div>
<!-- 如果需要分页器 -->
{% if section.settings.paginator %}
<div class="swiper-pagination"></div>
{% endif %}
<!-- 如果需要导航按钮 -->
{% if section.settings.navigation %}
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
{% endif %}
</div>
</div>
<script src="https://unpkg.com/swiper@8/swiper-bundle.min.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
new Swiper('.swiper-container', {
slidesPerView: 'auto',
spaceBetween: 10,
loop: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
},
autoplay: '{{ section.settings.play }}'
? {
delay: 3000, // 自动播放的延迟时间,单位为毫秒
stopOnLastSlide: false,
disableOnInteraction: false, // 用户操作后是否停止自动播放
}
: null,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
});
});
</script>
{% schema %}
{
"name": "轮播",
"settings": [
{
"type": "checkbox",
"id": "navigation",
"label": "左右箭头"
},
{
"type": "checkbox",
"id": "play",
"label": "是否自动播放"
},
{
"type": "checkbox",
"id": "paginator",
"label": "分页器"
},
{
"type": "color",
"id": "paginator_color",
"label": "分页器颜色",
"default": "#fff"
},
{
"type": "range",
"id": "desktop_image_height",
"min": 100,
"max": 1000,
"step": 10,
"unit": "px",
"label": "桌面图像行高",
"default": 460
},
{
"type": "range",
"id": "mobile_image_height",
"min": 100,
"max": 700,
"step": 10,
"unit": "px",
"label": "移动图像行高",
"default": 400
},
{
"type": "range",
"id": "image_width",
"min": 1,
"max": 100,
"step": 1,
"unit": "%",
"label": "图像的宽",
"default": 80
}
],
"blocks": [
{
"type": "images",
"name": "图片",
"settings": [
{
"type": "image_picker",
"label": "图片",
"id": "image"
},
{
"type": "url",
"label": "点击图片跳转的 url",
"id": "link_url"
}
]
}
],
"presets": [
{
"name": "轮播",
"blocks": [
{
"type": "image"
},
{
"type": "image"
},
{
"type": "image"
},
{
"type": "image"
}
]
}
]
}
{% endschema %}
五、创建一个 app
注:建议使用 pnpm
。
创建后报错处理
注:理论上 Shopify 支持 Vue 作为应用框架的开发。
1、创建应用前配置环境
1)登陆 Gadget
2)登陆 shopify partners
等商店创建成功。
3)根据 shopify partners 生成的信息去填写 Gadget
4)根据 Gadget 去填写 shopify partners
5)shopify 中安装程序
先写一个 hello word 查看效果。
6)Gadget 进行初步数据的创建
这步待定。
7)在本地监听 Gadget 的变化 🚮
npx @gadgetinc/ggt@latest sync --app 自己定义的名字 ~/gadget/自己定义的名字
8)本地开发
注:如果没安装,提示你安装 @shopify/create-app 。
npm init @shopify/app@latest
未完待续
六、注意事项
1、window.onload
window.onload 在一个 html 文件中,只执行一次
,所以 你在界面中,有时候它是不执行的,所以要尽量避免使用它(因为你不确定在别处是否使用),可以考虑使用 document.addEventListener("load", function() {}) 来替代,可参考:blog.csdn.net/m0_61420899…
document.addEventListener("load", function() {
})
2、shopify 缓存很严重
chrome://settings/clearBrowserData/
及时清理。
七、shopify配置 ⚠️
1、结账页税费和货到付款的运费都只能用插件处理
2、货到付款配置需要结合运费设置
八、GA4 (用户习惯收集)
注:必须要填写 你要收集的网站(不友好)。