# 面包屑组件

一个导航组件，显示用户在层次结构中的当前位置，帮助用户了解他们所在的位置并导航回之前的层级。

## 功能特性

- **层次导航**: 显示从根目录到当前位置的路径
- **可点击项目**: 导航到任何先前的层级（当前项除外）
- **自定义分隔符**: 可配置面包屑项目之间的分隔符
- **自定义数据**: 与面包屑项目关联任何数据
- **点击处理器**: 导航操作的自定义逻辑
- **响应式**: 适应容器宽度

## 基本用法

```svelte
<script>
import Breadcrumbs, { type Breadcrumb } from '@ticatec/uniface-element/Breadcrumbs';

const breadcrumbItems: Breadcrumb[] = [
  { label: '首页', data: { path: '/' } },
  { label: '产品', data: { path: '/products' } },
  { label: '电子产品', data: { path: '/products/electronics' } },
  { label: '智能手机', data: { path: '/products/electronics/smartphones' } }
];

const handleItemClick = (data: any) => (event: MouseEvent) => {
  console.log('导航到:', data.path);
  // 处理导航逻辑
};
</script>

<Breadcrumbs 
  items={breadcrumbItems} 
  onItemClick={handleItemClick} 
/>
```

## 属性参数

| 属性 | 类型 | 默认值 | 描述 |
|------|------|---------|-------------|
| `items` | `Breadcrumb[]` | `[]` | 面包屑项目数组 |
| `separator` | `string` | `"/"` | 项目之间的分隔符字符 |
| `onItemClick` | `(item: any) => (event: MouseEvent) => void` | - | 面包屑项目的点击处理器 |
| `style` | `string` | `''` | 自定义CSS样式 |

## 面包屑接口

```typescript
interface Breadcrumb {
  label: string;    // 面包屑的显示文本
  data: any;        // 关联数据（如路由、ID等）
}
```

## 使用示例

### 基础文件系统导航

```svelte
<script>
const fileSystemPath = [
  { label: '文档', data: { path: '/documents' } },
  { label: '项目', data: { path: '/documents/projects' } },
  { label: '我的应用', data: { path: '/documents/projects/myapp' } },
  { label: 'src', data: { path: '/documents/projects/myapp/src' } }
];

const navigateToFolder = (data: any) => (event: MouseEvent) => {
  window.location.href = data.path;
};
</script>

<Breadcrumbs 
  items={fileSystemPath}
  onItemClick={navigateToFolder}
  separator=" > "
/>
```

### 电商分类导航

```svelte
<script>
const categoryPath = [
  { label: '所有分类', data: { categoryId: null } },
  { label: '电子产品', data: { categoryId: 'electronics' } },
  { label: '计算机', data: { categoryId: 'computers' } },
  { label: '笔记本电脑', data: { categoryId: 'laptops' } }
];

const goToCategory = (data: any) => (event: MouseEvent) => {
  if (data.categoryId) {
    router.push(`/category/${data.categoryId}`);
  } else {
    router.push('/categories');
  }
};
</script>

<Breadcrumbs 
  items={categoryPath}
  onItemClick={goToCategory}
  separator=" › "
/>
```

### 管理面板导航

```svelte
<script>
const adminPath = [
  { label: '仪表板', data: { route: '/admin' } },
  { label: '用户管理', data: { route: '/admin/users' } },
  { label: '编辑用户', data: { route: '/admin/users/edit', userId: 123 } }
];

const navigateToAdminPage = (data: any) => (event: MouseEvent) => {
  // 自定义导航逻辑
  adminRouter.navigate(data.route);
};
</script>

<Breadcrumbs 
  items={adminPath}
  onItemClick={navigateToAdminPage}
/>
```

### 文档站点

```svelte
<script>
const docsPath = [
  { label: '文档', data: { section: 'home' } },
  { label: '组件', data: { section: 'components' } },
  { label: '表单控件', data: { section: 'forms' } },
  { label: '文本编辑器', data: { section: 'texteditor' } }
];

const goToDocsSection = (data: any) => (event: MouseEvent) => {
  scrollToSection(data.section);
};
</script>

<Breadcrumbs 
  items={docsPath}
  onItemClick={goToDocsSection}
  separator=" • "
/>
```

### 带图标的自定义分隔符

```svelte
<script>
const projectPath = [
  { label: '工作区', data: { id: 'workspace' } },
  { label: '项目 Alpha', data: { id: 'project-alpha' } },
  { label: '设置', data: { id: 'settings' } }
];
</script>

<Breadcrumbs 
  items={projectPath}
  onItemClick={handleNavigation}
  separator=" 🔹 "
  style="font-size: 14px; color: #666;"
/>
```

### 自定义样式

```svelte
<Breadcrumbs 
  items={breadcrumbs}
  onItemClick={navigate}
  separator=" / "
  style="
    background: #f8f9fa; 
    padding: 8px 16px; 
    border-radius: 4px; 
    font-size: 13px;
  "
/>
```

### 动态面包屑

```svelte
<script>
let currentPath = [];

// 基于当前路由构建面包屑
$: breadcrumbs = buildBreadcrumbs($page.url.pathname);

function buildBreadcrumbs(pathname) {
  const segments = pathname.split('/').filter(Boolean);
  const items = [{ label: '首页', data: { path: '/' } }];
  
  let currentPath = '';
  segments.forEach(segment => {
    currentPath += `/${segment}`;
    items.push({
      label: formatSegment(segment),
      data: { path: currentPath }
    });
  });
  
  return items;
}

function formatSegment(segment) {
  return segment.charAt(0).toUpperCase() + segment.slice(1);
}

const navigateTo = (data) => (event) => {
  goto(data.path);
};
</script>

<Breadcrumbs 
  items={breadcrumbs}
  onItemClick={navigateTo}
/>
```

## 行为特性

### 点击交互
- 除最后一项外，所有面包屑项目都可点击
- 最后一项（当前位置）不可点击，显示为纯文本
- 点击处理器接收来自面包屑项目的关联数据对象

### 导航模式
- 通常用于层次导航
- 帮助用户了解当前位置
- 提供快速访问父级层级的方式

## 样式定制

组件使用以下CSS类：

- `.uniface-breadcrumbs` - 主容器
- `.breadcrumb` - 单个面包屑项目

### CSS示例

```css
.uniface-breadcrumbs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
  font-size: 14px;
  color: #666;
}

.breadcrumb {
  cursor: pointer;
  color: #007acc;
  text-decoration: none;
}

.breadcrumb:hover {
  text-decoration: underline;
}

.breadcrumb:last-child {
  cursor: default;
  color: #333;
  font-weight: 500;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .uniface-breadcrumbs {
    font-size: 12px;
  }
}
```

## 常见模式

### 页面标题集成

```svelte
<div class="page-header">
  <Breadcrumbs items={breadcrumbs} onItemClick={navigate} />
  <h1>{currentPageTitle}</h1>
</div>
```

### 带加载状态

```svelte
<script>
let loading = false;
let breadcrumbs = [];

const loadBreadcrumbs = async (pageId) => {
  loading = true;
  try {
    breadcrumbs = await fetchBreadcrumbs(pageId);
  } finally {
    loading = false;
  }
};
</script>

{#if loading}
  <div class="breadcrumb-skeleton">加载中...</div>
{:else}
  <Breadcrumbs items={breadcrumbs} onItemClick={navigate} />
{/if}
```

### 截断长路径

```svelte
<script>
const MAX_ITEMS = 4;

$: displayItems = breadcrumbs.length > MAX_ITEMS
  ? [
      breadcrumbs[0],
      { label: '...', data: { truncated: true } },
      ...breadcrumbs.slice(-2)
    ]
  : breadcrumbs;

const handleClick = (data) => (event) => {
  if (data.truncated) {
    // 显示包含隐藏项目的下拉菜单
    showFullPath = true;
    return;
  }
  navigate(data);
};
</script>

<Breadcrumbs 
  items={displayItems}
  onItemClick={handleClick}
/>
```

## 无障碍访问

- 使用语义导航结构
- 为可点击和不可点击项目提供清晰的视觉区别
- 确保足够的颜色对比度
- 考虑为屏幕阅读器提供ARIA标签

```svelte
<nav aria-label="面包屑导航">
  <Breadcrumbs items={breadcrumbs} onItemClick={navigate} />
</nav>
```

## 路由集成

### SvelteKit集成

```svelte
<script>
import { page } from '$app/stores';
import { goto } from '$app/navigation';

$: breadcrumbs = generateBreadcrumbs($page.route.id);

function generateBreadcrumbs(routeId) {
  // 基于路由结构生成面包屑
  return routeSegments.map(segment => ({
    label: segment.title,
    data: { path: segment.path }
  }));
}

const navigate = (data) => (event) => {
  goto(data.path);
};
</script>

<Breadcrumbs items={breadcrumbs} onItemClick={navigate} />
```

### React Router集成

```javascript
// 仅供参考 - 类似模式可以适配
const breadcrumbs = useBreadcrumbs(routes);
```

## 最佳实践

1. **清晰层次**: 确保面包屑反映逻辑层次结构
2. **一致命名**: 在类似页面中使用一致的标签
3. **响应式设计**: 考虑面包屑在移动设备上的显示方式
4. **性能**: 不要过度嵌套面包屑层级
5. **用户上下文**: 基于用户入口点显示相关路径
6. **跳过导航**: 为无障碍访问提供跳过链接

## 移动设备考虑

对于移动设备，考虑：

```css
@media (max-width: 480px) {
  .uniface-breadcrumbs {
    overflow-x: auto;
    white-space: nowrap;
  }
  
  /* 或者只显示父级和当前页面 */
  .breadcrumb:not(:nth-last-child(2)):not(:last-child) {
    display: none;
  }
}
```

## 测试

测试面包屑时：

```javascript
// 测试导航
const breadcrumbs = [
  { label: '首页', data: { path: '/' } },
  { label: '产品', data: { path: '/products' } }
];

const mockNavigate = vi.fn();
render(Breadcrumbs, { 
  props: { items: breadcrumbs, onItemClick: mockNavigate } 
});

// 点击第一个面包屑
fireEvent.click(screen.getByText('首页'));
expect(mockNavigate).toHaveBeenCalledWith({ path: '/' });
```