问题求知者 2025-06-05 21:15 采纳率: 0%
浏览 20

在shopify制作一个基于html、css、js实现展示品牌发展历程的时间轴模板

我的html、css、js分别存放在sections/timeline-section.liquid、assets/timeline-section.css、assets/timeline-section.js中。(具体见附注2

img


)此外我已经上传SVG资源:
timeline-drop.svg (水滴图标) 具体为:https://cdn.shopify.com/s/files/1/0078/6156/7570/files/wd-page-brand-story-time-line-drop-svg.png
timeline-arrow.svg (箭头图标) 具体为:https://cdn.shopify.com/s/files/1/0078/6156/7570/files/wd-page-brand-story-time-line-drop-angle-svg.png
timeline-line.svg (时间轴线) 具体为:https://cdn.shopify.com/s/files/1/0078/6156/7570/files/wd-brand-story-time-line-svg.png
并且确保在theme.liquid中已添加GSAP:
{{ 'https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js' | script_tag | replace: '<script', '<script defer' }}
{{ 'https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollTrigger.min.js' | script_tag | replace: '<script', '<script defer' }}
我是以爬取他人的网站为参考,想制作了一个展示品牌发展历程的时间轴模板,以供shopify商店开发者使用,以便设计时可以在后台直接填充品牌近年的一些经典数据、图片,展示品牌的的发展历程。但是实现的效果不是很理想(效果如截图)。
问题:
1.当前界面随着鼠标的上下滚动,页面直接较快的瞬移水平到最后,能否页面随鼠标上下滚动而水平缓慢移动,像爬取的参考网站一样。(有点类似拖拉水平滚动的感觉,只不过现在是随鼠标上下滚动而水平缓慢移动)
2.爬取网站的时间轴是一条长长的粗直线,我的效果图是断点的直线,需要改成连续的直线。
3.时间轴项目应该在时间轴下方一定的距离,或者在时间轴上方一定的距离,(最好先下后上,如爬取网站一样排列)然后通过一定的粗线和圆点连接。而不是现在和时间轴重合,应该是容器位置设计问题。(截图就是现在时间轴项目的样式和位置)
4.显然我实现的界面也没有填充整个屏幕感觉是shopify主题的限制。(我将我自己的网站用F12爬取的html放在附注3)
请基于该代码和参考网站,重新生成源代码,注意区分。(注意:不用一比一复制爬取的参考网站,可以参照,关键是实现效果)
附注:
1.我爬取的参考网站地址是:https://www.waterdropfilter.com/pages/brand-story?ref=headermenu
2.源代码如下:

{%- comment -%}
  Timeline section for brand story
{%- endcomment -%}

{{ 'timeline-section.css' | asset_url | stylesheet_tag }}

<div class="timeline-section" id="timeline-{{ section.id }}">
  <div class="timeline-container">
    <div class="pin-spacer">
      <div class="timeline-wrapper">
        <div class="timeline-contents">
          <!-- 左侧固定内容 -->
          <div class="timeline-side timeline-first">
            <div class="timeline-title">
              {{ section.settings.title_line1 }}<br>
              {{ section.settings.title_line2 }}
            </div>
            <div class="timeline-description">
              {{ section.settings.description }}
            </div>
            <div class="timeline-icon">
              <div class="drop-icon">
                <img alt="" loading="lazy" src="{{ 'timeline-drop.svg' | asset_url }}" class="drop-img">
                <img alt="" loading="lazy" src="{{ 'timeline-arrow.svg' | asset_url }}" class="arrow-icon">
              </div>
            </div>
          </div>

          <!-- 时间轴主体 -->
          <div class="timeline-items">
            <div class="timeline-items-line">
              <img alt="" loading="lazy" src="{{ 'timeline-line.svg' | asset_url }}" role="presentation">
            </div>
            
            {% for block in section.blocks %}
              {% case block.type %}
                {% when 'year' %}
                  <div class="timeline-year">
                    {% if block.settings.year_image %}
                      <img alt="{{ block.settings.year_alt }}" loading="lazy" src="{{ block.settings.year_image | img_url: '300x' }}">
                    {% else %}
                      <div class="placeholder-year">{{ block.settings.year_alt }}</div>
                    {% endif %}
                  </div>
                
                {% when 'item' %}
                  <div class="timeline-item {% if block.settings.position == 'top' %}item-top{% endif %}">
                    <div class="timeline-connector">
                      <div class="timeline-item-info-line"></div>
                    </div>
                    {% if block.settings.link != blank %}
                      <a href="{{ block.settings.link }}" class="timeline-item-link">
                    {% endif %}
                      <div class="timeline-item-content">
                        {% if block.settings.image %}
                          <div class="timeline-item-image">
                            <img alt="{{ block.settings.image_alt }}" loading="lazy" src="{{ block.settings.image | img_url: '300x' }}">
                          </div>
                        {% endif %}
                        <div class="timeline-item-text">
                          {% if block.settings.title != blank %}
                            <div class="timeline-item-title">
                              {{ block.settings.title }}
                            </div>
                          {% endif %}
                          <div class="timeline-item-description">
                            {{ block.settings.description }}
                          </div>
                        </div>
                      </div>
                    {% if block.settings.link != blank %}
                      </a>
                    {% endif %}
                  </div>
              {% endcase %}
            {% endfor %}
          </div>

          <!-- 右侧固定内容 -->
          <div class="timeline-side timeline-last">
            <div class="timeline-title">
              {{ section.settings.title_line1 }}<br>
              <span>{{ section.settings.title_line2 }}</span>
            </div>
            <div class="timeline-description">
              {{ section.settings.description }}
            </div>
            <div class="timeline-icon">
              <div class="drop-icon bottom-icon">
                <img alt="" loading="lazy" src="{{ 'timeline-drop.svg' | asset_url }}" class="drop-img">
                <img alt="" loading="lazy" src="{{ 'timeline-arrow.svg' | asset_url }}" class="arrow-icon">
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

{% if section.blocks.size > 0 %}
  <script src="{{ 'timeline-section.js' | asset_url }}" defer="defer"></script>
{% endif %}

{% schema %}
{
  "name": "品牌时间轴",
  "tag": "section",
  "class": "section",
  "settings": [
    {
      "type": "text",
      "id": "title_line1",
      "label": "标题行1",
      "default": "Waterdrop"
    },
    {
      "type": "text",
      "id": "title_line2",
      "label": "标题行2",
      "default": "Filter's Growth"
    },
    {
      "type": "textarea",
      "id": "description",
      "label": "描述",
      "default": "Catch up on our progress in water purification area, consistently in pursuit of excellence, meaningful results, and a tech-focused emphasis since our inception."
    }
  ],
  "blocks": [
    {
      "type": "year",
      "name": "年份标记",
      "settings": [
        {
          "type": "image_picker",
          "id": "year_image",
          "label": "年份图片"
        },
        {
          "type": "text",
          "id": "year_alt",
          "label": "年份文本",
          "default": "2023"
        }
      ]
    },
    {
      "type": "item",
      "name": "时间轴项目",
      "settings": [
        {
          "type": "select",
          "id": "position",
          "label": "位置",
          "options": [
            {
              "value": "top",
              "label": "顶部"
            },
            {
              "value": "bottom",
              "label": "底部"
            }
          ],
          "default": "bottom"
        },
        {
          "type": "image_picker",
          "id": "image",
          "label": "图片"
        },
        {
          "type": "text",
          "id": "image_alt",
          "label": "图片替代文本"
        },
        {
          "type": "text",
          "id": "title",
          "label": "标题"
        },
        {
          "type": "richtext",
          "id": "description",
          "label": "描述"
        },
        {
          "type": "url",
          "id": "link",
          "label": "链接"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "品牌时间轴",
      "category": "自定义",
      "blocks": [
        {
          "type": "year",
          "settings": {
            "year_alt": "2015"
          }
        },
        {
          "type": "item",
          "settings": {
            "title": "品牌创立",
            "description": "<p>我们的品牌故事从这里开始</p>",
            "position": "bottom"
          }
        }
      ]
    }
  ]
}
{% endschema %}

/* 基础样式 */
.timeline-section {
  overflow: hidden;
  background: #036AFF;
  position: relative;
  padding: 0;
  margin: 0;
  width: 100%;
}

.timeline-container {
  width: 100%;
  height: auto;
  padding: 0;
  margin: 0;
}

.pin-spacer {
  width: 100% !important;
  height: auto !important;
  padding: 0 !important;
  margin: 0 !important;
}

.timeline-wrapper {
  height: 100vh;
  width: 100%;
  padding: 80px 0;
  margin: 0 auto;
  overflow: visible;
  position: relative;
}

.timeline-contents {
  display: flex;
  align-items: center;
  height: 100%;
  padding: 0 5%;
  position: relative;
  gap: 40px;
}

/* 侧边内容 */
.timeline-side {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 300px;
  flex-shrink: 0;
  padding: 20px;
  box-sizing: border-box;
  text-align: center;
}

.timeline-title {
  color: #fff;
  font-family: Montserrat, sans-serif;
  font-size: 36px;
  font-weight: 600;
  line-height: 125%;
  margin-bottom: 24px;
}

.timeline-title span {
  font-size: 24px;
}

.timeline-description {
  color: #fff;
  font-family: Montserrat, sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 150%;
  margin-bottom: 24px;
}

.timeline-icon {
  cursor: pointer;
}

.drop-icon {
  position: relative;
  display: inline-block;
}

.drop-img {
  display: block;
}

.arrow-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.bottom-icon {
  transform: rotate(180deg);
}

/* 时间轴主体 */
.timeline-items {
  position: relative;
  height: 100%;
  display: flex;
  align-items: center;
  flex-grow: 1;
  overflow: visible;
  gap: 40px;
}

/* 时间轴连接线 */
.timeline-items-line {
  height: 4px;
  width: 100%;
  background-color: #fff;
  position: absolute;
  top: 50%;
  left: 0;
  z-index: 0;
}

.timeline-items-line img {
  width: 100%;
  height: 100%;
}

.timeline-year {
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: 150px;
  z-index: 1;
}

.timeline-year img {
  max-width: 150px;
  max-height: 80px;
  object-fit: contain;
}

.placeholder-year {
  color: white;
  font-size: 24px;
  font-weight: bold;
  font-family: Montserrat, sans-serif;
}

.timeline-item {
  min-height: 200px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  position: relative;
  flex-shrink: 0;
  min-width: 250px;
  z-index: 1;
}

.item-top {
  justify-content: flex-start;
}

.timeline-connector {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
}

.timeline-item-info-line {
  position: absolute;
  height: 100px;
  width: 2px;
  background: #fff;
  top: 50%;
  transform: translateY(-50%);
  left: 50%;
}

.timeline-item-info-line::after {
  content: '';
  position: absolute;
  width: 8px;
  height: 8px;
  background: #fff;
  border-radius: 50%;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
}

.item-top .timeline-item-info-line {
  top: 0;
  transform: none;
}

.item-top .timeline-item-info-line::after {
  top: 0;
  bottom: auto;
}

.timeline-item-content {
  display: flex;
  gap: 20px;
  opacity: 1;
  transform: none;
  background: rgba(255, 255, 255, 0.1);
  padding: 20px;
  border-radius: 8px;
}

.timeline-item-image img {
  max-width: 200px;
  max-height: 150px;
  object-fit: cover;
  border-radius: 8px;
}

.timeline-item-text {
  max-width: 300px;
}

.timeline-item-title {
  color: #fff;
  font-family: Montserrat, sans-serif;
  font-size: 20px;
  font-weight: 600;
  line-height: 125%;
  margin-bottom: 8px;
}

.timeline-item-description {
  width: 240px;
  color: #fff;
  font-family: Montserrat, sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 150%;
}

/* 响应式设计 */
@media screen and (max-width: 1280px) {
  .timeline-title {
    font-size: 32px;
  }
  
  .timeline-side {
    width: 250px;
  }
}

@media screen and (max-width: 1024px) {
  .timeline-wrapper {
    padding: 40px 0;
    overflow-x: scroll;
  }
  
  .timeline-contents {
    padding: 0 10px;
  }
  
  .timeline-title {
    font-size: 24px;
  }
  
  .timeline-item-title {
    font-size: 16px;
  }
  
  .timeline-item-description {
    font-size: 14px;
    width: 180px;
  }
  
  .timeline-items-line {
    opacity: 0;
  }
}

@media screen and (max-width: 767px) {
  .timeline-side {
    width: 220px;
  }
  
  .timeline-description {
    font-size: 14px;
  }
  
  .timeline-year img {
    width: 130px;
  }
  
  .timeline-item-image img {
    width: 180px;
  }
}

document.addEventListener('DOMContentLoaded', function() {
  // 确保GSAP已加载
  if (typeof gsap === 'undefined' || typeof ScrollTrigger === 'undefined') {
    console.error('GSAP or ScrollTrigger is not loaded. Timeline section requires these libraries.');
    return;
  }

  // 注册插件
  gsap.registerPlugin(ScrollTrigger);

  // 初始化时间轴
  function initTimeline() {
    const sections = document.querySelectorAll('.timeline-section');
    
    sections.forEach(section => {
      const timelineContent = section.querySelector('.timeline-contents');
      const timelineItems = section.querySelectorAll('.timeline-contents > *');
      
      if (!timelineContent || timelineItems.length === 0) return;
      
      // 计算总宽度
      let totalWidth = 0;
      timelineItems.forEach(item => {
        totalWidth += item.offsetWidth + 40; // 40px间隙
      });
      
      // 设置容器宽度
      timelineContent.style.width = `${totalWidth}px`;
      
      // 创建平滑滚动动画
      gsap.to(timelineContent, {
        x: () => -(timelineContent.scrollWidth - window.innerWidth),
        ease: "none",
        scrollTrigger: {
          trigger: section,
          start: "top top",
          end: "bottom bottom",
          scrub: 1.5, // 控制滚动平滑度
          pin: true,
          anticipatePin: 1
        }
      });
    });
  }

  // 初始化时间轴
  initTimeline();
  
  // 窗口大小变化时刷新
  window.addEventListener('resize', function() {
    ScrollTrigger.refresh();
    initTimeline();
  });
});

  • 写回答

6条回答 默认 最新

  • 阿里嘎多学长 2025-06-05 21:25
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    解答

    你想在Shopify中创建一个基于HTML、CSS、JS的时间轴模板,用于展示品牌发展历程。下面是一个基本的解决方案:

    HTML结构

    <!-- timeline-section.liquid -->
    <div class="timeline">
      <div class="timeline-header">品牌发展历程</div>
      <div class="timeline-content">
        {% for event in events %}
        <div class="timeline-event">
          <div class="event-date">{{ event.date }}</div>
          <div class="event-description">{{ event.description }}</div>
        </div>
        {% endfor %}
      </div>
    </div>
    

    CSS样式

    /* timeline-section.css */
    .timeline {
      max-width: 800px;
      margin: 40px auto;
      padding: 20px;
      background-color: #f9f9f9;
      border: 1px solid #ddd;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    }
    
    .timeline-header {
      font-size: 24px;
      font-weight: bold;
      margin-bottom: 20px;
    }
    
    .timeline-content {
      padding: 20px;
    }
    
    .timeline-event {
      margin-bottom: 20px;
      padding: 10px;
      border-bottom: 1px solid #ccc;
    }
    
    .event-date {
      font-size: 18px;
      font-weight: bold;
      color: #666;
    }
    
    .event-description {
      font-size: 16px;
      color: #333;
    }
    

    JS逻辑

    // timeline-section.js
    const timelineEvents = [
      {
        date: '2010-01-01',
        description: '品牌成立'
      },
      {
        date: '2012-06-01',
        description: '首次获得投资'
      },
      {
        date: '2015-03-01',
        description: '品牌扩展到新市场'
      },
      // ...
    ];
    
    document.addEventListener('DOMContentLoaded', () => {
      const timeline = document.querySelector('.timeline');
      const events = timelineEvents.map((event) => {
        const eventHTML = `
          <div class="timeline-event">
            <div class="event-date">${event.date}</div>
            <div class="event-description">${event.description}</div>
          </div>
        `;
        return eventHTML;
      });
      timeline.innerHTML = events.join('');
    });
    

    这个解决方案使用了Liquid模板语言来渲染HTML结构,使用CSS样式来美化时间轴的外观,使用JavaScript来动态地生成时间轴内容。请注意,这只是一个基本的示例代码,你需要根据自己的需求进行修改和扩展。

    希望这个解决方案能够帮助你实现你的需求。如果你有任何问题或需要更多帮助,请随时问我。

    评论

报告相同问题?

问题事件

  • 创建了问题 6月5日