Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
364 changes: 358 additions & 6 deletions docs/content/docs/2.components/5.navigation/01.tabs.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Tabs 标签页"
description: "用于在多个内容面板之间切换的导航组件"
badge: Dev
badge: Beta
authors:
- name: sKy
username: skiyee
Expand All @@ -10,11 +10,363 @@ authors:
target: _blank
links:
- label: Source
icon: radix-icons:github-logo
to: https://github.com/skiyee/ui/blob/main/uni-ui/src/components/sk-tabs.vue
icon: i-radix-icons:github-logo
to: https://github.com/skiyee/ui/blob/main/packages/skiyee-uni-ui/src/components/sk-tabs.vue
target: _blank
---

::warning
该组件目前处于开发阶段,诚挚邀请开发者们访问 [GitHub仓库](https://github.com/skiyee/ui){:target="_blank"} 参与技术讨论或提交贡献
::
::CodePreview{path="/pages-navigation/tabs/base" height="300"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/base.vue" code no-name -->

```vue
<script setup lang="ts">
import { ref } from 'vue'

const activeIndex = ref(0)
</script>

<template>
<SkTabs v-model="activeIndex">
<SkTab label="标签一">
<view class="p-4">内容一</view>
</SkTab>
<SkTab label="标签二">
<view class="p-4">内容二</view>
</SkTab>
<SkTab label="标签三">
<view class="p-4">内容三</view>
</SkTab>
</SkTabs>
</template>
```

<!-- /automd -->
::

## 用法

### DefaultValue 默认激活

| Prop | 类型 | 默认值 | 描述 |
|----------------|----------|--------|----------------------------------|
| `defaultValue` | `number` | `0` | 默认激活的标签索引(非受控模式) |

::CodePreview{path="/pages-navigation/tabs/default-value" height="300"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/default-value.vue" code no-name -->

```vue
<template>
<SkTabs :default-value="1">
<SkTab label="标签一">
<view class="p-4">内容一</view>
</SkTab>
<SkTab label="标签二">
<view class="p-4">内容二(默认激活)</view>
</SkTab>
<SkTab label="标签三">
<view class="p-4">内容三</view>
</SkTab>
</SkTabs>
</template>
```

<!-- /automd -->
::

### Controlled 受控模式

| Prop | 类型 | 默认值 | 描述 |
|--------------|----------|--------|-------------------------------------------|
| `v-model` | `number` | - | 当前激活的标签索引,支持 v-model 双向绑定 |

::CodePreview{path="/pages-navigation/tabs/controlled" height="400"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/controlled.vue" code no-name -->

```vue
<script setup lang="ts">
import { ref } from 'vue'

const activeIndex = ref(0)

function switchToSecondTab() {
activeIndex.value = 1
}
</script>

<template>
<view class="flex flex-col gap-3 p-4">
<SkButton label="切换到第二个标签" @click="switchToSecondTab" />

<SkTabs v-model="activeIndex">
<SkTab label="标签一">
<view class="p-4">内容一</view>
</SkTab>
<SkTab label="标签二">
<view class="p-4">内容二</view>
</SkTab>
<SkTab label="标签三">
<view class="p-4">内容三</view>
</SkTab>
</SkTabs>
</view>
</template>
```

<!-- /automd -->
::

### Scrollable 横向滚动

| Prop | 类型 | 默认值 | 描述 |
|--------------|-----------|---------|----------------|
| `scrollable` | `boolean` | `false` | 是否可横向滚动 |

::CodePreview{path="/pages-navigation/tabs/scrollable" height="300"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/scrollable.vue" code no-name -->

```vue
<script setup lang="ts">
import { ref } from 'vue'

const activeIndex = ref(0)
</script>

<template>
<SkTabs v-model="activeIndex" scrollable>
<SkTab
v-for="i in 10"
:key="i"
:label="`标签${i}`"
>
<view class="p-4">内容 {{ i }}</view>
</SkTab>
</SkTabs>
</template>
```

<!-- /automd -->
::

### LineWidth 指示器宽度

| Prop | 类型 | 默认值 | 描述 |
|--------------|----------------------|----------|-------------------|
| `lineWidth` | `number \| 'auto'` | `'auto'` | 指示器宽度(px) |

::CodePreview{path="/pages-navigation/tabs/line" height="600"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/line.vue" code no-name -->

```vue
<script setup lang="ts">
import { ref } from 'vue'

const activeIndex = ref(0)
</script>

<template>
<view class="flex flex-col gap-4 p-4">
<view>
<text class="text-sm text-label mb-2">自动宽度(默认)</text>
<SkTabs v-model="activeIndex" line-width="auto">
<SkTab label="标签一">内容一</SkTab>
<SkTab label="标签二">内容二</SkTab>
</SkTabs>
</view>

<view>
<text class="text-sm text-label mb-2">固定宽度</text>
<SkTabs v-model="activeIndex" :line-width="60">
<SkTab label="标签一">内容一</SkTab>
<SkTab label="标签二">内容二</SkTab>
</SkTabs>
</view>

</view>
</template>
```

<!-- /automd -->
::

### Animated 切换动画

| Prop | 类型 | 默认值 | 描述 |
|------------|-----------|--------|------------------|
| `animated` | `boolean` | `true` | 是否启用切换动画 |

::CodePreview{path="/pages-navigation/tabs/animated" height="500"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/animated.vue" code no-name -->

```vue
<script setup lang="ts">
import { ref } from 'vue'

const activeIndex = ref(0)
</script>

<template>
<view class="flex flex-col gap-4 p-4">
<view>
<text class="text-sm text-label mb-2">启用动画(默认)</text>
<SkTabs v-model="activeIndex" :animated="true">
<SkTab label="标签一">内容一</SkTab>
<SkTab label="标签二">内容二</SkTab>
</SkTabs>
</view>

<view>
<text class="text-sm text-label mb-2">禁用动画</text>
<SkTabs v-model="activeIndex" :animated="false">
<SkTab label="标签一">内容一</SkTab>
<SkTab label="标签二">内容二</SkTab>
</SkTabs>
</view>
</view>
</template>
```

<!-- /automd -->
::

### Disabled 禁用状态

| Prop | 类型 | 默认值 | 描述 |
|------------|-----------|---------|---------------------|
| `disabled` | `boolean` | `false` | 是否禁用整个标签页 |

::CodePreview{path="/pages-navigation/tabs/disabled" height="500"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/disabled.vue" code no-name -->

```vue
<script setup lang="ts">
import { ref } from 'vue'

const activeIndex = ref(0)
</script>

<template>
<view class="flex flex-col gap-4 p-4">
<view>
<text class="text-sm text-label mb-2">禁用整个标签页</text>
<SkTabs v-model="activeIndex" disabled>
<SkTab label="标签一">内容一</SkTab>
<SkTab label="标签二">内容二</SkTab>
</SkTabs>
</view>

<view>
<text class="text-sm text-label mb-2">禁用单个标签</text>
<SkTabs v-model="activeIndex">
<SkTab label="正常标签">内容一</SkTab>
<SkTab label="禁用标签" disabled>内容二</SkTab>
<SkTab label="正常标签">内容三</SkTab>
</SkTabs>
</view>
</view>
</template>
```

<!-- /automd -->
::

## 用法 (Tab)

### Label 标签文本

| Prop | 类型 | 默认值 | 描述 |
|---------|----------|--------|----------|
| `label` | `string` | - | 标签文本 |

### 监听切换事件

通过监听 `change` 和 `click` 事件可以在标签切换时执行自定义逻辑。

::CodePreview{path="/pages-navigation/tabs/events" height="300"}
<!-- automd:file src="../../../../../examples/uni/src/pages-navigation/tabs/events.vue" code no-name -->

```vue
<script setup lang="ts">
import { ref } from 'vue'

const activeIndex = ref(0)

function handleChange(index: number) {
console.log('切换到标签:', index)
uni.showToast({
title: `切换到标签 ${index + 1}`,
icon: 'none'
})
}

function handleClick(index: number) {
console.log('点击了标签:', index)
}
</script>

<template>
<SkTabs
v-model="activeIndex"
@change="handleChange"
@click="handleClick"
>
<SkTab label="标签一">
<view class="p-4">内容一</view>
</SkTab>
<SkTab label="标签二">
<view class="p-4">内容二</view>
</SkTab>
<SkTab label="标签三">
<view class="p-4">内容三</view>
</SkTab>
</SkTabs>
</template>
```

<!-- /automd -->
::

## 接口 (Tabs)

### Props

| 属性名 | 类型 | 默认值 | 描述 |
|----------------|---------------------|----------|--------------------------------------------------------------|
| `v-model` | `number` | - | 详见 [Controlled 受控模式](#controlled-受控模式) |
| `defaultValue` | `number` | `0` | 详见 [DefaultValue 默认激活](#defaultvalue-默认激活) |
| `scrollable` | `boolean` | `false` | 详见 [Scrollable 横向滚动](#scrollable-横向滚动) |
| `lineWidth` | `number \| 'auto'` | `'auto'` | 详见 [LineWidth 指示器宽度](#linewidth-指示器宽度) |
| `animated` | `boolean` | `true` | 详见 [Animated 切换动画](#animated-切换动画) |
| `disabled` | `boolean` | `false` | 详见 [Disabled 禁用状态](#disabled-禁用状态) |
| `clax` | `SkTabsUcvProps['clax']` | - | 用于扩展当前基础样式 |

### Emits

| 事件名 | 参数 | 描述 |
|----------|-------------------|----------------|
| `change` | `(index: number)` | 切换标签时触发 |
| `click` | `(index: number)` | 点击标签时触发 |

### Slots

| 插槽名 | 说明 |
|-----------|------------------------------|
| `default` | 标签内容,放置 `SkTab` 组件 |

## 接口 (Tab)

### Props

| 属性名 | 类型 | 默认值 | 描述 |
|------------|-----------|---------|----------------------------------------|
| `label` | `string` | - | 详见 [Label 标签文本](#label-标签文本) |
| `disabled` | `boolean` | `false` | 是否禁用该标签 |

### Slots

| 插槽名 | 说明 |
|-----------|----------------|
| `default` | 标签面板内容 |

## 交互

正在完善中,敬请期待!😊
2 changes: 1 addition & 1 deletion docs/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default defineNuxtConfig({
],
runtimeConfig: {
public: {
demo: 'bundle',
demo: 'http://localhost:5173/#/',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

避免硬编码 localhost URL

将 demo URL 硬编码为 http://localhost:5173/#/ 会在生产环境或其他开发环境中失效。

建议使用环境变量配置:

   runtimeConfig: {
     public: {
-      demo: 'http://localhost:5173/#/',
+      demo: process.env.DEMO_URL || 'http://localhost:5173/#/',
     },
   },

或在项目根目录创建 .env 文件:

DEMO_URL=http://localhost:5173/#/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
demo: 'http://localhost:5173/#/',
demo: process.env.DEMO_URL || 'http://localhost:5173/#/',
🤖 Prompt for AI Agents
In docs/nuxt.config.ts around line 9 the demo URL is hardcoded as
"http://localhost:5173/#/" which breaks in non-local environments; replace the
hardcoded string with a value read from an environment variable (e.g.
process.env.DEMO_URL or via Nuxt runtime/config) and ensure you provide a
default fallback for local dev, add instructions to create a .env file with
DEMO_URL if needed, and update project docs or README to document the new
DEMO_URL environment variable.

},
},
})
Loading