Просмотр исходного кода

✨ feat(category): add CategorySidebarItem component

- create CategorySidebarItem component with basic functionality
- add CSS styles for category sidebar item with active, disabled and hover states
- implement context integration with parent CategorySidebar component
- add type definitions for component props
- export component through category index file
yourname 1 месяц назад
Родитель
Сommit
27889f1752

+ 72 - 0
mini/src/components/category/CategorySidebarItem/CategorySidebarItem.css

@@ -0,0 +1,72 @@
+/* CategorySidebarItem 组件样式 */
+.category-sidebar-item {
+  display: flex;
+  justify-content: center;
+  text-align: center;
+  background-color: #f5f5f5;
+  color: #222427;
+  padding: 20rpx 0;
+  font-size: 26rpx;
+}
+
+.category-sidebar-item.active {
+  position: relative;
+  background: white;
+}
+
+.category-sidebar-item.active::before {
+  content: '';
+  position: absolute;
+  width: 6rpx;
+  height: 48rpx;
+  background-color: #fa4126;
+  left: 0;
+  top: 50%;
+  transform: translate(0, -50%);
+  border-radius: 64rpx;
+}
+
+.category-sidebar-item__text {
+  width: 136rpx;
+  height: 36rpx;
+  padding: 8rpx 0;
+  line-height: 36rpx;
+  text-align: center;
+  font-size: 28rpx;
+  color: #666666;
+}
+
+.category-sidebar-item.active .category-sidebar-item__text {
+  background-color: white;
+  border-radius: 36rpx;
+  color: #fa4126;
+}
+
+.text-overflow {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.top-right-radius {
+  border-top-right-radius: 16rpx;
+}
+
+.bottom-right-radius {
+  border-bottom-right-radius: 16rpx;
+}
+
+.category-sidebar-item-container {
+  background-color: white;
+}
+
+/* 禁用状态 */
+.category-sidebar-item.disabled {
+  opacity: 0.5;
+  cursor: not-allowed;
+}
+
+/* 悬停效果 */
+.category-sidebar-item--hover {
+  opacity: 0.7;
+}

+ 116 - 0
mini/src/components/category/CategorySidebarItem/index.tsx

@@ -0,0 +1,116 @@
+import React, { useState, useContext, useEffect, useCallback } from 'react';
+import { View } from '@tarojs/components';
+import { CategorySidebarContext } from '../CategorySidebar';
+import './CategorySidebarItem.css';
+
+export interface CategorySidebarItemProps {
+  /** 标题 */
+  title?: string;
+  /** 是否禁用 */
+  disabled?: boolean;
+  /** 自定义类名 */
+  className?: string;
+  /** 点击事件回调 */
+  onClick?: (index: number) => void;
+  /** 子组件 */
+  children?: React.ReactNode;
+}
+
+const CategorySidebarItem: React.FC<CategorySidebarItemProps> = (props) => {
+  const { title, disabled = false, className = '', onClick, children } = props;
+
+  const [selected, setSelected] = useState<boolean>(false);
+  const [topRightRadius, setTopRightRadius] = useState<boolean>(false);
+  const [bottomRightRadius, setBottomRightRadius] = useState<boolean>(false);
+
+  const context = useContext(CategorySidebarContext);
+  const itemRef = React.useRef<any>(null);
+
+  // 注册到父组件
+  useEffect(() => {
+    if (context) {
+      context.registerItem(itemRef.current);
+      return () => {
+        context.unregisterItem(itemRef.current);
+      };
+    }
+  }, [context]);
+
+  // 设置选中状态
+  const setActive = useCallback((isActive: boolean) => {
+    return new Promise<void>((resolve) => {
+      setSelected(isActive);
+      resolve();
+    });
+  }, []);
+
+  // 设置顶部圆角
+  const setTopRightRadiusMethod = useCallback((val: boolean) => {
+    return new Promise<void>((resolve) => {
+      setTopRightRadius(val);
+      resolve();
+    });
+  }, []);
+
+  // 设置底部圆角
+  const setBottomRightRadiusMethod = useCallback((val: boolean) => {
+    return new Promise<void>((resolve) => {
+      setBottomRightRadius(val);
+      resolve();
+    });
+  }, []);
+
+  // 暴露方法给父组件
+  useEffect(() => {
+    itemRef.current = {
+      setActive,
+      setTopRightRadius: setTopRightRadiusMethod,
+      setBottomRightRadius: setBottomRightRadiusMethod,
+    };
+  }, [setActive, setTopRightRadiusMethod, setBottomRightRadiusMethod]);
+
+  // 点击事件处理
+  const handleClick = useCallback(() => {
+    if (!context || disabled) {
+      return;
+    }
+
+    // 获取当前项在父组件中的索引
+    const index = context.activeKey;
+
+    // 设置选中状态
+    context.setActive(index).then(() => {
+      // 触发点击事件
+      if (onClick) {
+        onClick(index);
+      }
+    });
+  }, [context, disabled, onClick]);
+
+  // 构建类名
+  const itemClassNames = [
+    'category-sidebar-item',
+    selected ? 'active' : '',
+    disabled ? 'disabled' : '',
+    topRightRadius ? 'top-right-radius' : '',
+    bottomRightRadius ? 'bottom-right-radius' : '',
+    className,
+  ].filter(Boolean).join(' ');
+
+  return (
+    <View className="category-sidebar-item-container">
+      <View
+        className={itemClassNames}
+        hoverClass="category-sidebar-item--hover"
+        hoverStayTime={70}
+        onClick={handleClick}
+      >
+        <View className="category-sidebar-item__text text-overflow">
+          {title || children}
+        </View>
+      </View>
+    </View>
+  );
+};
+
+export default CategorySidebarItem;

+ 5 - 0
mini/src/components/category/index.ts

@@ -0,0 +1,5 @@
+// 导出商品分类相关组件
+export { default as CategorySidebar } from './CategorySidebar';
+export { default as CategorySidebarItem } from './CategorySidebarItem';
+export type { CategorySidebarProps } from './CategorySidebar';
+export type { CategorySidebarItemProps } from './CategorySidebarItem';