【提问】前端小白,自己配合AI写了一个多级搜索功能,卡在JS导数据-2. Shopify 优化论坛-Shopify-Shopify 问答社区

提问前端小白,自己配合AI写了一个多级搜索功能,卡在JS导数据

微信截图_20250413151855

下拉菜单没有数据,不知道是啥情况。元字段的id没有输错,但是用下面的调试代码,调试值为null;(代码是用的DS V3写的,提示词用的基本和up160视频一样)

<!-- 在Liquid中检查元字段原始值 -->
{% assign test_product = collections.all.products.first %}
Make: {{ test_product.metafields.custom.car_make | json }}
Model: {{ test_product.metafields.custom.car_model | json }}
Year: {{ test_product.metafields.custom.specifications | json }}

Js部分是这样的

<script>
document.addEventListener('DOMContentLoaded', function() {
  // 获取所有产品数据(严格按您提供的元字段类型)
  const allProducts = [];
  {% for product in collections.all.products %}
    allProducts.push({
      id: {{ product.id | json }},
      title: {{ product.title | json }},
      // 严格按元字段类型处理:
      make: {{ product.metafields.custom.car_make | json }} || null,  // 单行文本
      model: {{ product.metafields.custom.car_model | json }} || null, // 单行文本
      year: {% if product.metafields.custom.specifications %} 
              {{ product.metafields.custom.specifications | times: 1 | json }} // 强制转为整数
            {% else %} 
              null 
            {% endif %}
    });
  {% endfor %}

  // 构建筛选缓存(严格区分文本和数字类型)
  const filterCache = {
    // 品牌列表(单行文本)
    makes: [...new Set(allProducts
      .map(p => p.make)
      .filter(m => typeof m === 'string' && m.trim() !== ''))].sort(),
    
    // 车型字典 {make: [model1, model2]}
    models: allProducts.reduce((acc, product) => {
      if (typeof product.make === 'string' && 
          typeof product.model === 'string' &&
          product.make.trim() !== '' && 
          product.model.trim() !== '') {
        acc[product.make] = [...new Set([...(acc[product.make] || []), product.model])];
      }
      return acc;
    }, {}),
    
    // 年份字典 {make|model: [year1, year2]}(整数)
    years: allProducts.reduce((acc, product) => {
      if (typeof product.make === 'string' && 
          typeof product.model === 'string' &&
          Number.isInteger(product.year) &&
          product.make.trim() !== '' && 
          product.model.trim() !== '') {
        const key = `${product.make}|${product.model}`;
        acc[key] = [...new Set([...(acc[key] || []), product.year])]
          .sort((a, b) => b - a); // 年份降序
      }
      return acc;
    }, {})
  };

  // DOM元素
  const makeFilter = document.getElementById('make-filter');
  const modelFilter = document.getElementById('model-filter');
  const yearFilter = document.getElementById('year-filter');
  const searchButton = document.getElementById('search-button');
  const resultsContainer = document.getElementById('search-results');

  // 品牌选择变化时
  makeFilter.addEventListener('change', function() {
    const make = this.value;
    
    // 重置下级筛选器
    modelFilter.innerHTML = '<option value="">All Models</option>';
    yearFilter.innerHTML = '<option value="">All Years</option>';
    yearFilter.disabled = true;
    searchButton.disabled = true;
    
    if (make) {
      // 动态填充车型选项(单行文本)
      const models = filterCache.models[make] || [];
      models.forEach(model => {
        const option = new Option(model, model);
        modelFilter.add(option);
      });
      modelFilter.disabled = models.length === 0;
    } else {
      modelFilter.disabled = true;
    }
  });

  // 车型选择变化时
  modelFilter.addEventListener('change', function() {
    const make = makeFilter.value;
    const model = this.value;
    
    // 重置年份选择器
    yearFilter.innerHTML = '<option value="">All Years</option>';
    searchButton.disabled = true;
    
    if (make && model) {
      // 动态填充年份选项(整数)
      const years = filterCache.years[`${make}|${model}`] || [];
      years.forEach(year => {
        const option = new Option(year, year);
        yearFilter.add(option);
      });
      yearFilter.disabled = years.length === 0;
    } else {
      yearFilter.disabled = true;
    }
  });

  // 执行搜索(严格类型比较)
  searchButton.addEventListener('click', function() {
    const make = makeFilter.value;
    const model = modelFilter.value;
    const year = yearFilter.value;
    
    const results = allProducts.filter(product => {
      const makeMatch = !make || product.make === make;
      const modelMatch = !model || product.model === model;
      // 年份比较:输入是字符串,元字段是整数,需转换类型
      const yearMatch = !year || product.year === parseInt(year, 10);
      return makeMatch && modelMatch && yearMatch;
    });
    
    renderResults(results);
  });

  // 渲染结果函数(类型安全显示)
  function renderResults(products) {
    resultsContainer.innerHTML = '';
    
    if (!products.length) {
      resultsContainer.innerHTML = '<p class="no-results">No matching products found</p>';
      return;
    }
    
    products.forEach(product => {
      const card = document.createElement('div');
      card.className = 'product-card';
      card.innerHTML = `
        <a href="/products/${product.handle}">
          <h3>${product.title}</h3>
          <div class="product-meta">
            ${product.make ? `<span>Make: ${product.make}</span>` : ''}
            ${product.model ? `<span>Model: ${product.model}</span>` : ''}
            ${product.year ? `<span>Year: ${product.year}</span>` : ''}
          </div>
        </a>
      `;
      resultsContainer.appendChild(card);
    });
  }
});
</script>

Liquid部分

<!-- 在 sections/multi-level-search.liquid 中 -->
<div class="multi-level-search">
  <div class="search-filters">
    <!-- 第一级:品牌选择 (Make) -->
    <div class="filter-group">
      <label for="make-filter">Make</label>
      <select id="make-filter" class="filter-select">
        <option value="">All Makes</option>
        {% comment %} 动态生成品牌选项(单行文本类型){% endcomment %}
        {% assign all_makes = "" | split: "," %}
        {% for product in collections.all.products %}
          {% assign make = product.metafields.custom.car_make | strip | default: "" %}
          {% if make != "" %}
            {% assign all_makes = all_makes | push: make %}
          {% endif %}
        {% endfor %}
        {% assign unique_makes = all_makes | uniq | sort %}
        
        {% for make in unique_makes %}
          <option value="{{ make | escape }}">{{ make }}</option>
        {% endfor %}
      </select>
    </div>
    
    <!-- 第二级:车型选择 (Model) -->
    <div class="filter-group">
      <label for="model-filter">Model</label>
      <select id="model-filter" class="filter-select" disabled>
        <option value="">Select Make First</option>
      </select>
    </div>
    
    <!-- 第三级:年份选择 (Year) -->
    <div class="filter-group">
      <label for="year-filter">Year</label>
      <select id="year-filter" class="filter-select" disabled>
        <option value="">Select Model First</option>
      </select>
    </div>
    
    <button id="search-button" class="search-btn" disabled>Search</button>
  </div>
  
  <div id="search-results" class="search-results-grid"></div>
</div>

元字段里是有值的

image

image

 

 

 

请登录后发表评论