1.0.1 • Published 1 month ago

@tanzhenxing/zx-goods-category v1.0.1

Weekly downloads
-
License
ISC
Repository
-
Last release
1 month ago

Category 分类

用于展示商品分类的组件,支持左右布局,左侧为分类列表,右侧为子分类网格展示。

特性

  • 🎯 左右布局 - 经典的分类展示布局
  • 🎨 高度自定义 - 支持自定义样式、字段映射、插槽等
  • 📱 多端兼容 - 支持 H5、小程序、App
  • 🔄 响应式 - 支持动态数据更新
  • 🎪 丰富插槽 - 提供多个插槽满足不同需求
  • 性能优化 - 使用 scroll-view 优化滚动性能

引入

import zxCategory from '@/components/zx-category/zx-category.vue'

基础用法

<template>
  <zx-category 
    :categories="categories"
    v-model:active-index="activeIndex"
    @category-click="onCategoryClick"
    @sub-category-click="onSubCategoryClick"
    style="height: 600rpx;"
  ></zx-category>
</template>

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

const activeIndex = ref(0)

const categories = reactive([
  {
    id: 1,
    name: '手机数码',
    children: [
      { id: 101, name: '手机', image: 'https://img.yzcdn.cn/vant/cat.jpeg' },
      { id: 102, name: '平板电脑', image: 'https://img.yzcdn.cn/vant/cat.jpeg' },
      { id: 103, name: '智能手表', image: 'https://img.yzcdn.cn/vant/cat.jpeg' }
    ]
  },
  {
    id: 2,
    name: '服装鞋帽',
    children: [
      { id: 201, name: '男装', image: 'https://img.yzcdn.cn/vant/cat.jpeg' },
      { id: 202, name: '女装', image: 'https://img.yzcdn.cn/vant/cat.jpeg' },
      { id: 203, name: '童装', image: 'https://img.yzcdn.cn/vant/cat.jpeg' }
    ]
  }
])

const onCategoryClick = (data) => {
  console.log('分类点击:', data)
}

const onSubCategoryClick = (data) => {
  console.log('子分类点击:', data)
}
</script>

自定义列数

<template>
  <zx-category 
    :categories="categories"
    :columns="4"
    style="height: 600rpx;"
  ></zx-category>
</template>

自定义字段映射

当你的数据结构与默认字段不同时,可以通过字段映射来适配:

<template>
  <zx-category 
    :categories="customCategories"
    category-key="categoryId"
    category-name-key="categoryName"
    sub-categories-key="subList"
    sub-category-key="subId"
    sub-name-key="subName"
    sub-image-key="subImage"
  ></zx-category>
</template>

<script setup>
const customCategories = [
  {
    categoryId: 1,
    categoryName: '电子产品',
    subList: [
      { subId: 101, subName: '笔记本电脑', subImage: 'xxx.jpg' }
    ]
  }
]
</script>

自定义插槽

左侧分类项插槽

<template>
  <zx-category :categories="categories">
    <template #left-item="{ item, index, active }">
      <view class="custom-left-item">
        <zx-icon v-if="item.icon" :name="item.icon" :color="active ? '#ff6900' : '#666'"></zx-icon>
        <text :style="{ color: active ? '#ff6900' : '#333' }">{{ item.name }}</text>
        <view v-if="item.badge" class="badge">{{ item.badge }}</view>
      </view>
    </template>
  </zx-category>
</template>

右侧头部插槽

<template>
  <zx-category :categories="categories">
    <template #right-header="{ category }">
      <view class="custom-header">
        <text class="title">{{ category.name }}</text>
        <text class="desc">{{ category.desc || '精选推荐' }}</text>
      </view>
    </template>
  </zx-category>
</template>

子分类项插槽

<template>
  <zx-category :categories="categories">
    <template #sub-item="{ item, index, category }">
      <view class="custom-sub-item">
        <image :src="item.image" class="image" />
        <text class="name">{{ item.name }}</text>
        <text v-if="item.price" class="price">¥{{ item.price }}</text>
      </view>
    </template>
  </zx-category>
</template>

空状态插槽

<template>
  <zx-category :categories="categories">
    <template #empty>
      <view class="custom-empty">
        <zx-icon name="inbox" size="80rpx" color="#ddd"></zx-icon>
        <text>暂无数据</text>
      </view>
    </template>
  </zx-category>
</template>

API

Props

参数说明类型默认值
categories分类数据Array[]
active-index当前激活的分类索引,支持 v-modelNumber|String0
category-key分类唯一标识字段名String'id'
category-name-key分类名称字段名String'name'
sub-categories-key子分类数组字段名String'children'
sub-category-key子分类唯一标识字段名String'id'
sub-name-key子分类名称字段名String'name'
sub-image-key子分类图片字段名String'image'
left-width左侧分类列表宽度(rpx)Number|String200
columns右侧网格列数Number|String3
show-category-title是否显示分类标题Booleantrue
show-border是否显示子分类项边框Booleantrue
show-empty是否显示空状态Booleantrue
show-scrollbar是否显示滚动条Booleanfalse
scroll-with-animation滚动时是否使用动画Booleantrue
empty-text空状态文本String'暂无数据'
custom-class自定义类名String''
custom-style自定义样式Object{}

Events

事件名说明回调参数
category-click分类点击时触发{ item, index, category }
sub-category-click子分类点击时触发{ item, index, category, categoryIndex }
update:active-index激活索引更新时触发index

Slots

插槽名说明参数
left-item自定义左侧分类项内容{ item, index, active }
right-header自定义右侧头部内容{ category }
sub-item自定义子分类项内容{ item, index, category }
right-footer自定义右侧底部内容{ category }
empty自定义空状态内容-

Methods

通过 ref 可以获取到 Category 实例并调用实例方法:

方法名说明参数返回值
setActiveIndex设置激活的分类索引index: number-
getCurrentCategory获取当前激活的分类-object
getCurrentSubCategories获取当前激活分类的子分类列表-array
scrollToTop滚动到顶部--
<template>
  <zx-category ref="categoryRef" :categories="categories"></zx-category>
</template>

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

const categoryRef = ref()

// 设置激活分类
const setActive = () => {
  categoryRef.value.setActiveIndex(2)
}

// 获取当前分类
const getCurrent = () => {
  const current = categoryRef.value.getCurrentCategory()
  console.log(current)
}
</script>

数据结构

基础数据结构

const categories = [
  {
    id: 1,                    // 分类ID
    name: '手机数码',          // 分类名称
    badge: 'HOT',             // 徽标(可选)
    children: [               // 子分类列表
      {
        id: 101,              // 子分类ID
        name: '手机',          // 子分类名称
        image: 'xxx.jpg',     // 子分类图片
        badge: 'NEW'          // 徽标(可选)
      }
    ]
  }
]

自定义字段结构

const customCategories = [
  {
    categoryId: 1,            // 自定义分类ID字段
    categoryName: '电子产品',  // 自定义分类名称字段
    subList: [                // 自定义子分类数组字段
      {
        subId: 101,           // 自定义子分类ID字段
        subName: '笔记本',     // 自定义子分类名称字段
        subImage: 'xxx.jpg'   // 自定义子分类图片字段
      }
    ]
  }
]

样式定制

组件提供了丰富的 CSS 变量,可以方便地进行样式定制:

.zx-category {
  // 左侧分类样式
  &__left {
    background-color: #fff;
    
    &-item {
      padding: 32rpx 24rpx;
      
      &--active {
        background-color: #f8f8f8;
        border-right: 6rpx solid #ff6900;
      }
    }
    
    &-text {
      font-size: 28rpx;
      color: #323233;
    }
  }
  
  // 右侧内容样式
  &__right {
    background-color: #fff;
    
    &-title {
      font-size: 32rpx;
      font-weight: 600;
      color: #323233;
    }
  }
  
  // 网格样式
  &__grid {
    &-item {
      padding: 32rpx 16rpx;
      background-color: #fff;
      border-radius: 12rpx;
    }
    
    &-text {
      font-size: 24rpx;
      color: #323233;
    }
  }
}

注意事项

  1. 容器高度:组件需要设置明确的高度才能正常滚动
  2. 图片资源:确保图片资源可访问,建议使用 CDN
  3. 数据格式:确保数据结构符合组件要求
  4. 性能优化:大量数据时建议使用虚拟滚动
  5. 兼容性:在小程序中使用时注意图片域名配置

常见问题

Q: 如何实现分类数据的异步加载?

A: 可以在分类点击时动态加载子分类数据:

<script setup>
const onCategoryClick = async (data) => {
  // 显示加载状态
  uni.showLoading({ title: '加载中...' })
  
  try {
    // 异步加载子分类数据
    const subCategories = await loadSubCategories(data.item.id)
    
    // 更新数据
    categories[data.index].children = subCategories
  } catch (error) {
    console.error('加载失败:', error)
  } finally {
    uni.hideLoading()
  }
}
</script>

Q: 如何实现左右联动滚动?

A: 组件内部已实现基础联动,如需更复杂的联动效果,可以监听滚动事件:

<template>
  <zx-category 
    :categories="categories"
    @scroll="onScroll"
  ></zx-category>
</template>

<script setup>
const onScroll = (e) => {
  // 处理滚动联动逻辑
  console.log('滚动位置:', e.detail.scrollTop)
}
</script>

Q: 如何自定义空状态样式?

A: 使用 empty 插槽:

<template>
  <zx-category :categories="categories">
    <template #empty>
      <view class="custom-empty">
        <image src="/static/empty.png" class="empty-image" />
        <text class="empty-text">暂无商品分类</text>
        <button class="empty-button" @click="refresh">刷新</button>
      </view>
    </template>
  </zx-category>
</template>
1.0.1

1 month ago