跳转至主要内容
Shopify 产品详情页

第 260 期 Shopify 动态化产品展示 短视频展示模块 视频卷轴功能分享

前言

短视频展示模块是当今电商网站,尤其是 Shopify 网站上一种非常流行且高效的视觉营销工具。它的核心目的是将社交媒体上引人入胜的短视频体验,无缝集成到在线购物流程中。

其用途和价值主要包括以下几个方面:

动态化产品展示

例如:展示产品如何工作、展示产品实际效果、展示产品材质和细节、展示用户反馈或使用评价,完全超越静态图片。

解决用户 “这个产品实际用起来怎么样?” 的核心疑问,降低不确定性,提高订单转化。

建立社会认同和信任

视频,尤其是用户生成内容 (UGC) 的视频,具有极强的真实性和说服力。

  • 客户评价视频:真实客户在使用产品后拍摄的视频,是比任何文字好评都更有力的推荐
  • 开箱视频 (Unboxing):展示客户收到产品时的完整体验,营造一种期待感和满足感。
  • 网红或 KOL 合作视频:利用影响力人物的背书,快速建立品牌信誉。

打消潜在客户的疑虑,利用口碑效应促进销售。

讲述品牌故事,增加互动

除了以上两个方面之外,这个视频模块还可以用来展示品牌故事、幕后花絮、甚至生产视频。

同时视频也会更加吸引眼球,提升客户互动的同时增加页面停留时间。

此次分享的功能采用直接选择 Shopify 店铺中上传的视频的方式,支持上传任意视频到店铺后台进行使用,自带 Shopify CDN,且无需像 YouTube 嵌入那样引入大量第三方代码。

Shopify Video Reel Section

增强版主题

这个功能原本是我最近添加到增强版主题中的一项更新,不过本篇教程也提供免费版本,这样既照顾了使用增强版主题的用户的权益,也让免费用户可以体验到类似或者说大致的效果,结合视频演示就能知道增强版主题中完整功能的使用效果。

支持设置是否自动播放、视频卡片数量没有限制、手机端支持滑动查看更多视频。

如果你想进一步了解增强版主题,可以查看 主题介绍页面更新日志主题使用手册

Shopify Video Reel

免费版本

参考视频演示,创建一个 Section 文件:

video-carousel.liquid

粘贴以下代码并保存之后,即可在主题编辑器中添加模块进行使用(详见视频演示)。

<section class="video-reel-{{ section.id }}"
  style="
    --pt: {{ section.settings.padding_top | default: 0 }}px;
    --pb: {{ section.settings.padding_bottom | default: 0 }}px;
    --mt: {{ section.settings.margin_top | default: 0 }}px;
    --mb: {{ section.settings.margin_bottom | default: 0 }}px;
  "
>
  <style>
    .video-reel-{{ section.id }}{
      width:100%;
      margin: var(--mt) auto var(--mb);
      max-width: {{ section.settings.max_width | default: 1200 }}px;
      padding: var(--pt) 12px var(--pb);
      --reel-gap: {{ section.settings.card_gap | default: 20 }}px;
      --h-size-m: {{ section.settings.heading_size_mobile | default: 22 }}px;
      --h-size-d: {{ section.settings.heading_size_desktop | default: 28 }}px;
      --s-size-m: {{ section.settings.subheading_size_mobile | default: 14 }}px;
      --s-size-d: {{ section.settings.subheading_size_desktop | default: 16 }}px;
      --header-align: {{ section.settings.heading_align | default: 'center' }};
      --header-spacing: {{ section.settings.header_spacing | default: 16 }}px;
      --vt-size-m: {{ section.settings.video_title_size_mobile | default: 14 }}px;
      --vt-size-d: {{ section.settings.video_title_size_desktop | default: 14 }}px;
    }

    .video-reel-{{ section.id }} .reel-header{ 
      margin-bottom: var(--header-spacing);
      text-align: var(--header-align);
    }
    .video-reel-{{ section.id }} .reel-heading{
      margin:0; line-height:1.15; color:#000; font-weight:700;
      font-size: var(--h-size-m);
    }
    .video-reel-{{ section.id }} .reel-subheading{
      margin:.25rem 0 0; line-height:1.4; color:#000; font-weight:500;
      font-size: var(--s-size-m);
    }
    @media (min-width:1024px){
      .video-reel-{{ section.id }} .reel-heading{ font-size: var(--h-size-d); }
      .video-reel-{{ section.id }} .reel-subheading{ font-size: var(--s-size-d); }
    }

    .video-reel-{{ section.id }} .reel-track{
      display:flex; gap:var(--reel-gap);
      overflow-x:auto; -webkit-overflow-scrolling:touch;
      scroll-snap-type:x mandatory; padding-bottom:6px;
      justify-content:flex-start;
      cursor:grab; user-select:none;
    }
    @media (min-width:1024px){
      .video-reel-{{ section.id }} .reel-track{ justify-content:center; }
    }
    .video-reel-{{ section.id }} .reel-track::-webkit-scrollbar{ display:none; }

    .video-reel-{{ section.id }} .reel-card{
      scroll-snap-align:center; flex:0 0 auto; width:146px;
    }

    .video-reel-{{ section.id }} .video-box{
      position:relative; width:100%;
      height:207px;                         
      border-radius:14px; overflow:hidden; background:#111; display:block;
      
    }
    .video-reel-{{ section.id }} .video-box img{ width:100%; height:100%; object-fit:cover; display:block; }

    .video-reel-{{ section.id }} .reel-play{
      position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
      width:52px; height:52px; border-radius:9999px;
      background:rgba(255,255,255,.94);
      display:grid; place-items:center; border:none; cursor:pointer;
      box-shadow:0 1px 6px rgba(0,0,0,.25);
    }
    .video-reel-{{ section.id }} .reel-play svg{ width:22px; height:22px; fill:#000; }

    .video-reel-{{ section.id }} .video-title{
      text-align:center; color:#000; font-weight:600;
      margin-top:12px; font-size:14px;
    }

    .reel-lightbox[hidden]{ display:none !important; }
    .reel-lightbox{
      position:fixed; inset:0; z-index:9999; background:rgba(0,0,0,.7);
      display:grid; place-items:center; padding:16px;
    }
    .reel-lightbox .reel-lightbox-inner{
      position:relative;
      height:min(90vh, 800px);
      aspect-ratio: 9 / 16;
      display:grid; place-items:center;
      max-width:90vw;
    }
    .reel-lightbox video,
    .reel-lightbox .shopify-video{
      width:100%; height:100%; object-fit:cover; border-radius:12px; background:#000;
    }
    .reel-lightbox .close-btn{
      position:absolute; top:8px; right:8px; width:40px; height:40px;
      border-radius:9999px; display:grid; place-items:center; border:none; cursor:pointer;
      background:#fff; box-shadow:0 1px 6px rgba(0,0,0,.2); z-index:2;
    }
    .reel-lightbox .close-btn svg{ width:18px; height:18px; }

    .reel-lightbox .unmute-chip{
      position:absolute; left:10px; bottom:10px;
      padding:8px 12px; border:0; border-radius:9999px;
      background:rgba(0,0,0,.75); color:#fff; font-weight:600;
      display:flex; align-items:center; gap:8px; cursor:pointer;
      box-shadow:0 2px 8px rgba(0,0,0,.3);
    }
    .reel-lightbox .unmute-chip svg{ width:16px; height:16px; fill:#fff; }
  </style>

  {% if section.settings.heading != blank or section.settings.subheading != blank %}
    <header class="reel-header">
      {% if section.settings.heading != blank %}<h2 class="reel-heading">{{ section.settings.heading }}</h2>{% endif %}
      {% if section.settings.subheading != blank %}<p class="reel-subheading">{{ section.settings.subheading }}</p>{% endif %}
    </header>
  {% endif %}

  <div class="reel-track" id="reel-track-{{ section.id }}">
    {% for block in section.blocks %}
      {% if block.type == 'video_card' %}
        {% assign poster = '' %}
        {% if block.settings.poster_image != blank %}
          {% assign poster = block.settings.poster_image | image_url: width: 900 %}
        {% elsif block.settings.video != blank and block.settings.video.preview_image != blank %}
          {% assign poster = block.settings.video.preview_image | image_url: width: 900 %}
        {% endif %}

        <div class="reel-card" {{ block.shopify_attributes }}>
          <button class="video-box" type="button" data-modal="video-modal-{{ block.id }}" aria-label="Play {{ block.settings.title | escape }}">
            {% if poster != blank %}<img src="{{ poster }}" alt="">{% endif %}
            <span class="reel-play" aria-hidden="true">
              <svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
            </span>
          </button>
          {% if block.settings.title != blank %}<div class="video-title">{{ block.settings.title }}</div>{% endif %}
        </div>

        <div class="reel-lightbox" id="video-modal-{{ block.id }}" hidden>
          <div class="reel-lightbox-inner">
            <button class="close-btn" data-close aria-label="Close video">
              <svg viewBox="0 0 24 24"><path d="M18.3 5.7 12 12l6.3 6.3-1.4 1.4L10.6 13.4 4.3 19.7 2.9 18.3 9.2 12 2.9 5.7 4.3 4.3 10.6 10.6 16.9 4.3z"/></svg>
            </button>
            {% if block.settings.video != blank %}
              {{ block.settings.video | media_tag: autoplay: true, controls: true, loop: false, playsinline: true, preload: 'metadata' }}
            {% elsif block.settings.video_url != blank %}
              <video autoplay muted playsinline controls preload="metadata">
                <source src="{{ block.settings.video_url }}" type="video/mp4">
              </video>
            {% endif %}
          </div>
        </div>
      {% endif %}
    {% endfor %}
  </div>

  <script>
  (function(){
    const root = document.currentScript.closest('.video-reel-{{ section.id }}');
    if(!root) return;


    function openIntoBody(modal){
      const live = modal.cloneNode(true);
      live.id = modal.id + '--live';
      live.hidden = false;
      document.body.appendChild(live);

      const v = live.querySelector('video');

      function showUnmute(){
        if (live.querySelector('.unmute-chip')) return;
        const chip = document.createElement('button');
        chip.type = 'button';
        chip.className = 'unmute-chip';
        chip.setAttribute('aria-label', 'Turn sound on');
        chip.innerHTML = '<svg viewBox="0 0 24 24"><path d="M3 10v4h4l5 5V5L7 10H3zM16.5 12c0-1.77-1.02-3.29-2.5-4.03v8.06A4.49 4.49 0 0 0 16.5 12zm2.5 0c0 3.04-1.72 5.64-4.25 6.92v-2.2a5.997 5.997 0 0 0 0-9.44v-2.2C19.28 6.36 21 8.96 21 12z"/></svg><span>Tap for sound</span>';
        (live.querySelector('.reel-lightbox-inner') || live).appendChild(chip);
        chip.addEventListener('click', () => {
          if (!v) return;
          try {
            v.muted = false;
            const p = v.play?.();
            if (p && p.catch) p.catch(()=>{});
            chip.remove();
          } catch(e){}
        });
      }

      if (v) {
        try {
          v.playsInline = true;
          v.muted = false;                   
          let p = v.play?.();
          if (p && p.catch){
            p.catch(() => {                  
              try { v.muted = true; v.play?.(); } catch(e){}
              showUnmute();
            });
          }
        } catch(e) {
          try { v.muted = true; v.play?.(); showUnmute(); } catch(e2){}
        }
      }

      function close(){
        try{ if(v){ v.pause(); } }catch(e){}
        live.remove();
        document.documentElement.style.overflow = '';
      }

      live.addEventListener('click', e=>{
        if (e.target === live || e.target.closest('[data-close]')) close();
      });
      const onKey = (e)=>{ if(e.key === 'Escape'){ close(); document.removeEventListener('keydown', onKey);} };
      document.addEventListener('keydown', onKey);

      document.documentElement.style.overflow = 'hidden';
    }

    root.querySelectorAll('.video-box').forEach(btn=>{
      btn.addEventListener('click', ()=>{
        const m = document.getElementById(btn.getAttribute('data-modal'));
        if(!m) return;
        openIntoBody(m);
      });
    });

    const track = root.querySelector('#reel-track-{{ section.id }}');
    const setStart = () => {
      if (window.matchMedia('(max-width:1023px)').matches) track.scrollLeft = 0;
    };
    setStart(); window.addEventListener('resize', setStart);

    let isDown = false, startX = 0, startLeft = 0;
    const onDown = (e) => {
      isDown = true;
      startX = (e.touches ? e.touches[0].pageX : e.pageX);
      startLeft = track.scrollLeft;
    };
    const onMove = (e) => {
      if(!isDown) return;
      const x = (e.touches ? e.touches[0].pageX : e.pageX);
      track.scrollLeft = startLeft - (x - startX);
      e.preventDefault();
    };
    const onUp = () => { isDown = false; };

    track.addEventListener('mousedown', onDown);
    track.addEventListener('mousemove', onMove);
    track.addEventListener('mouseup', onUp);
    track.addEventListener('mouseleave', onUp);

    track.addEventListener('touchstart', onDown, { passive: true });
    track.addEventListener('touchmove', onMove, { passive: false });
    track.addEventListener('touchend', onUp);
    track.addEventListener('dragstart', (e)=>e.preventDefault());
  })();
</script>

</section>

{% schema %}
{
  "name": "Video Reel (Carousel)",
  "settings": [
    { "type": "text", "id": "heading", "label": "Heading", "default": "Watch more" },
    { "type": "text", "id": "subheading", "label": "Subheading" },
    { "type": "select", "id": "heading_align", "label": "Heading/Subheading alignment", "default": "center",
      "options": [ { "value": "left", "label": "Left" }, { "value": "center", "label": "Center" }, { "value": "right", "label": "Right" } ]
    },
    { "type": "range", "id": "heading_size_mobile",    "label": "Heading size (mobile, px)",    "default": 22, "min": 10, "max": 60, "step": 1 },
    { "type": "range", "id": "heading_size_desktop",   "label": "Heading size (desktop, px)",   "default": 28, "min": 10, "max": 80, "step": 1 },
    { "type": "range", "id": "subheading_size_mobile", "label": "Subheading size (mobile, px)", "default": 14, "min": 8,  "max": 40, "step": 1 },
    { "type": "range", "id": "subheading_size_desktop","label": "Subheading size (desktop, px)","default": 16, "min": 8,  "max": 48, "step": 1 },
    { "type": "range", "id": "header_spacing", "label": "Space below heading (px)", "default": 16, "min": 0, "max": 64, "step": 1 },
    { "type": "range", "id": "card_gap", "label": "Gap between cards (px)", "default": 20, "min": 8, "max": 40, "step": 1 },
    { "type": "range", "id": "max_width", "label": "Max content width (px)", "default": 1200, "min": 800, "max": 1600, "step": 10 },
    { "type": "header", "content": "Section spacing" },
    { "type": "range", "id": "padding_top", "label": "Padding top", "default": 0, "min": 0, "max": 80, "step": 2 },
    { "type": "range", "id": "padding_bottom", "label": "Padding bottom", "default": 0, "min": 0, "max": 80, "step": 2 },
    { "type": "range", "id": "margin_top", "label": "Margin top", "default": 0, "min": 0, "max": 120, "step": 2 },
    { "type": "range", "id": "margin_bottom", "label": "Margin bottom", "default": 0, "min": 0, "max": 120, "step": 2 },
    { "type": "range", "id": "video_title_size_mobile",  "label": "Video title size (mobile, px)",  "default": 14, "min": 8,  "max": 32, "step": 1 },
    { "type": "range", "id": "video_title_size_desktop", "label": "Video title size (desktop, px)", "default": 14, "min": 8,  "max": 40, "step": 1 }
  ],
  "blocks": [
    {
      "type": "video_card",
      "name": "Video card",
      "settings": [
        { "type": "text", "id": "title", "label": "Title under video" },
        { "type": "image_picker", "id": "poster_image", "label": "Poster image (thumbnail)" },
        { "type": "video", "id": "video", "label": "Video (select from Files/Library)" },
        { "type": "url", "id": "video_url", "label": "Fallback MP4 URL (if no video selected)" }
      ]
    }
  ],
  "max_blocks": 12,
  "presets": [ { "name": "Video Reel (Carousel)" } ]
}
{% endschema %}