npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tanzhenxing/zx-product-feed

v1.0.1

Published

`zx-product-feed` 是一个功能丰富的商品流组件,支持多种布局模式(网格、瀑布流、列表),常用于商品列表、搜索结果、推荐商品等场景。组件提供了完整的商品展示功能,包括图片、标题、价格、销量等信息的展示,同时支持加载更多、空状态等交互功能。

Readme

zx-product-feed 商品流组件

介绍

zx-product-feed 是一个功能丰富的商品流组件,支持多种布局模式(网格、瀑布流、列表),常用于商品列表、搜索结果、推荐商品等场景。组件提供了完整的商品展示功能,包括图片、标题、价格、销量等信息的展示,同时支持加载更多、空状态等交互功能。

特性

  • 🎨 支持三种布局模式:网格、瀑布流、列表
  • 📱 完美适配 H5、小程序、APP
  • 🔧 灵活的数据字段映射
  • 🖼️ 支持图片懒加载和错误处理
  • 📄 支持加载更多和分页功能
  • 🎯 丰富的自定义配置选项
  • 🎪 提供多个插槽支持自定义内容
  • 🎨 支持自定义颜色和样式
  • 📊 支持空状态展示

安装使用

pages.json 中引入组件:

{
  "easycom": {
    "^zx-(.*)$": "@/components/zx-$1/zx-$1.vue"
  }
}

基本用法

网格布局

<template>
  <zx-product-feed
    :list="productList"
    layout="grid"
    :columns="2"
    @item-click="handleItemClick"
    @load-more="handleLoadMore"
  />
</template>

<script setup>
import { ref } from 'vue'

const productList = ref([
  {
    id: 1,
    image: 'https://example.com/product1.jpg',
    title: '商品标题1',
    desc: '商品描述信息',
    price: 99.99,
    originalPrice: 199.99,
    sales: 1234,
    tag: '热销'
  },
  {
    id: 2,
    image: 'https://example.com/product2.jpg',
    title: '商品标题2',
    desc: '商品描述信息',
    price: 159.99,
    sales: 567
  }
])

const handleItemClick = ({ item, index }) => {
  console.log('点击商品:', item, index)
}

const handleLoadMore = () => {
  console.log('加载更多')
  // 加载更多数据的逻辑
}
</script>

瀑布流布局

<template>
  <zx-product-feed
    :list="productList"
    layout="waterfall"
    :columns="2"
    :gap="16"
  />
</template>

列表布局

<template>
  <zx-product-feed
    :list="productList"
    layout="list"
    :columns="1"
  />
</template>

自定义字段映射

<template>
  <zx-product-feed
    :list="customProductList"
    key-field="productId"
    image-field="thumbnail"
    title-field="name"
    desc-field="description"
    price-field="currentPrice"
    original-price-field="marketPrice"
    sales-field="soldCount"
    tag-field="label"
  />
</template>

<script setup>
const customProductList = ref([
  {
    productId: 'p001',
    thumbnail: 'https://example.com/thumb1.jpg',
    name: '自定义商品名称',
    description: '自定义商品描述',
    currentPrice: 88.88,
    marketPrice: 168.88,
    soldCount: 999,
    label: '新品'
  }
])
</script>

自定义商品卡片

<template>
  <zx-product-feed :list="productList">
    <template #item="{ item, index }">
      <view class="custom-card" @click="handleCustomClick(item, index)">
        <image :src="item.image" class="custom-image" />
        <view class="custom-content">
          <text class="custom-title">{{ item.title }}</text>
          <text class="custom-price">¥{{ item.price }}</text>
        </view>
      </view>
    </template>
  </zx-product-feed>
</template>

<style>
.custom-card {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  border-radius: 16rpx;
  padding: 20rpx;
  color: white;
}

.custom-image {
  width: 100%;
  height: 200rpx;
  border-radius: 12rpx;
}

.custom-content {
  margin-top: 16rpx;
}

.custom-title {
  font-size: 28rpx;
  font-weight: bold;
  display: block;
  margin-bottom: 8rpx;
}

.custom-price {
  font-size: 32rpx;
  font-weight: 600;
}
</style>

加载状态管理

<template>
  <zx-product-feed
    :list="productList"
    :loading="loading"
    :finished="finished"
    loading-text="正在加载..."
    finished-text="已加载全部商品"
    @load-more="loadMoreProducts"
  />
</template>

<script setup>
import { ref } from 'vue'

const productList = ref([])
const loading = ref(false)
const finished = ref(false)
const page = ref(1)

const loadMoreProducts = async () => {
  if (loading.value || finished.value) return
  
  loading.value = true
  try {
    // 模拟API请求
    const response = await fetchProducts(page.value)
    
    if (response.data.length === 0) {
      finished.value = true
    } else {
      productList.value.push(...response.data)
      page.value++
    }
  } catch (error) {
    console.error('加载失败:', error)
  } finally {
    loading.value = false
  }
}

// 模拟API请求
const fetchProducts = (pageNum) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      const mockData = pageNum <= 3 ? [
        // 模拟数据...
      ] : []
      resolve({ data: mockData })
    }, 1000)
  })
}

// 初始加载
loadMoreProducts()
</script>

自定义空状态

<template>
  <zx-product-feed :list="[]">
    <template #empty>
      <view class="custom-empty">
        <image src="/static/empty-cart.png" class="empty-image" />
        <text class="empty-text">暂无商品</text>
        <button class="empty-btn" @click="refreshData">刷新重试</button>
      </view>
    </template>
  </zx-product-feed>
</template>

<style>
.custom-empty {
  text-align: center;
  padding: 120rpx 40rpx;
}

.empty-image {
  width: 200rpx;
  height: 200rpx;
  margin-bottom: 32rpx;
}

.empty-text {
  display: block;
  font-size: 28rpx;
  color: #999;
  margin-bottom: 32rpx;
}

.empty-btn {
  background: #007aff;
  color: white;
  border: none;
  border-radius: 8rpx;
  padding: 16rpx 32rpx;
  font-size: 28rpx;
}
</style>

头部和底部插槽

<template>
  <zx-product-feed :list="productList">
    <template #header>
      <view class="feed-header">
        <text class="header-title">推荐商品</text>
        <text class="header-subtitle">为您精选优质好货</text>
      </view>
    </template>
    
    <template #footer>
      <view class="feed-footer">
        <text class="footer-text">— 到底了 —</text>
      </view>
    </template>
  </zx-product-feed>
</template>

<style>
.feed-header {
  padding: 40rpx 20rpx;
  text-align: center;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
}

.header-title {
  display: block;
  font-size: 36rpx;
  font-weight: bold;
  margin-bottom: 8rpx;
}

.header-subtitle {
  font-size: 24rpx;
  opacity: 0.8;
}

.feed-footer {
  padding: 40rpx;
  text-align: center;
}

.footer-text {
  font-size: 24rpx;
  color: #999;
}
</style>

API

Props

| 参数 | 说明 | 类型 | 默认值 | |------|------|------|--------| | list | 商品数据列表 | Array | [] | | layout | 布局模式:grid/waterfall/list | String | 'grid' | | columns | 列数 | Number | 2 | | gap | 间距(rpx) | Number | 20 | | keyField | 唯一标识字段名 | String | 'id' | | imageField | 图片字段名 | String | 'image' | | titleField | 标题字段名 | String | 'title' | | descField | 描述字段名 | String | 'desc' | | priceField | 价格字段名 | String | 'price' | | originalPriceField | 原价字段名 | String | 'originalPrice' | | salesField | 销量字段名 | String | 'sales' | | tagField | 标签字段名 | String | 'tag' | | imageMode | 图片裁剪模式 | String | 'aspectFill' | | lazyLoad | 是否懒加载图片 | Boolean | true | | showPrice | 是否显示价格 | Boolean | true | | showSales | 是否显示销量 | Boolean | true | | showLoadMore | 是否显示加载更多 | Boolean | true | | titleLines | 标题显示行数 | Number | 2 | | currency | 货币符号 | String | '¥' | | loading | 是否加载中 | Boolean | false | | finished | 是否加载完成 | Boolean | false | | loadingText | 加载中文本 | String | '加载中...' | | loadMoreText | 加载更多文本 | String | '点击加载更多' | | finishedText | 加载完成文本 | String | '没有更多了' | | emptyText | 空状态文本 | String | '暂无商品' | | titleColor | 标题颜色 | String | '#333' | | descColor | 描述颜色 | String | '#666' | | priceColor | 价格颜色 | String | '#ff4757' | | originalPriceColor | 原价颜色 | String | '#999' | | salesColor | 销量颜色 | String | '#999' | | tagColor | 标签文字颜色 | String | '#fff' | | tagBgColor | 标签背景颜色 | String | '#ff4757' | | customClass | 自定义类名 | String | '' | | customStyle | 自定义样式 | Object/String | {} |

Events

| 事件名 | 说明 | 回调参数 | |--------|------|----------| | item-click | 点击商品项 | { item, index } | | load-more | 加载更多 | - | | image-error | 图片加载错误 | { item, index } | | image-load | 图片加载成功 | { item, index } |

Slots

| 插槽名 | 说明 | 参数 | |--------|------|------| | header | 头部内容 | - | | item | 自定义商品项 | { item, index } | | empty | 空状态内容 | - | | loadMore | 自定义加载更多 | - | | footer | 底部内容 | - |

数据结构

商品数据结构

{
  id: 1,                    // 唯一标识
  image: 'image_url',       // 商品图片
  title: '商品标题',         // 商品标题
  desc: '商品描述',          // 商品描述
  price: 99.99,             // 当前价格
  originalPrice: 199.99,    // 原价
  sales: 1234,              // 销量
  tag: '热销'               // 标签
}

主题定制

组件提供了丰富的 CSS 变量,可用于自定义样式:

.zx-product-feed {
  // 卡片样式
  --card-bg: #fff;
  --card-border-radius: 12rpx;
  --card-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
  
  // 文字颜色
  --title-color: #333;
  --desc-color: #666;
  --price-color: #ff4757;
  --original-price-color: #999;
  --sales-color: #999;
  
  // 标签样式
  --tag-color: #fff;
  --tag-bg-color: #ff4757;
  --tag-border-radius: 6rpx;
  
  // 加载状态
  --loading-color: #007aff;
  --loading-text-color: #666;
}

注意事项

  1. 瀑布流布局在小程序中可能存在兼容性问题,建议优先使用网格布局
  2. 图片建议使用 CDN 地址,并设置合适的尺寸以提升加载性能
  3. 大量数据时建议启用虚拟滚动或分页加载以提升性能
  4. 自定义插槽时注意保持样式一致性
  5. 在使用自定义字段映射时,确保数据结构的正确性

兼容性

  • ✅ H5
  • ✅ 微信小程序
  • ✅ 支付宝小程序
  • ✅ 百度小程序
  • ✅ 字节跳动小程序
  • ✅ QQ小程序
  • ✅ 快手小程序
  • ✅ 京东小程序
  • ✅ App

许可证

MIT License