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
42 changes: 42 additions & 0 deletions docs/component/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,41 @@ const tab = ref('Design')
</wd-tabs>
```

## 插槽演示

可以通过 `nav-left` 和 `nav-right` 插槽,分别在标签导航栏的左侧和右侧添加自定义内容。

```html
<wd-tabs v-model="tab" sticky>
<template #nav-left>
<view class="tab-nav-slot">
<wd-icon name="filter" size="16px"></wd-icon>
</view>
</template>
<block v-for="item in 4" :key="item">
<wd-tab :title="`标签${item}`">
<view class="large">内容{{ item }}</view>
</wd-tab>
</block>
<template #nav-right>
<view class="tab-nav-slot">
<wd-icon name="add-circle1" size="16px"></wd-icon>
</view>
</template>
</wd-tabs>
```

```scss
.tab-nav-slot {
align-self: stretch;
padding: 0 8px;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
}
```

---

标签页在标签数大于等于 6 个时,可以滑动;当标签数大于等于 10 个时,将会显示导航地图,便于快速定位到某个标签。可以通过设置 `slidable-num` 修改可滑动的数量阈值;设置 `map-num` 修改显示导航地图的阈值。`slidable`设置为`always`时,所有的标签会向左侧收缩对齐,超出即可滑动。
Expand Down Expand Up @@ -299,6 +334,13 @@ function handlePopupShow() {
| scrollIntoView | 使选中项滚动到可视区域 | - | - |
| updateLineStyle | 更新激活项边框线样式,参数`animation`用于是否开启动画,默认开启 | `(animation: boolean) => void` | - |

## Tabs Slots
| name | 说明 | 参数 | 最低版本 |
| ------ | -------------------- | ----------------------- | -------- |
| nav-left | 标签栏左侧内容 | - | $LOWEST_VERSION$ |
| nav-right | 标签栏右侧内容 | - | $LOWEST_VERSION$ |


## 外部样式类

| 类名 | 说明 | 最低版本 |
Expand Down
1 change: 1 addition & 0 deletions src/locale/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
"cha-cao-huan-qi": "Slot wake-up",
"cha-cao-nei-rong": "Slot content",
"cha-cao-yong-fa": "Slot usage",
"cha-cao-yan-shi": "Slot demonstration",
"cha-cao-zi-ding-yi-tu-pian-nei-rong": "Slot custom image content",
"cha-kan": "view",
"cha-kan-geng-duo": "See more",
Expand Down
1 change: 1 addition & 0 deletions src/locale/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@
"cha-cao": "插槽",
"cha-cao-huan-qi": "插槽唤起",
"cha-cao-nei-rong": "插槽内容",
"cha-cao-yan-shi": "插槽演示",
"cha-cao-yong-fa": "插槽用法",
"cha-cao-zi-ding-yi-tu-pian-nei-rong": "插槽自定义图片内容",
"cha-kan": "查看",
Expand Down
29 changes: 29 additions & 0 deletions src/subPages/tabs/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@
</wd-tabs>
</demo-block>

<demo-block :title="$t('cha-cao-yan-shi')" transparent>
<wd-tabs v-model="tab12" sticky>
<template #nav-left>
<view class="tab-nav-slot">
<wd-icon name="filter" size="16px"></wd-icon>
</view>
</template>
<block v-for="item in 4" :key="item">
<wd-tab :title="$t('biao-qian-item') + item">
<view class="large">{{ $t('nei-rong') }}{{ tab12 + 1 }}</view>
</wd-tab>
</block>
<template #nav-right>
<view class="tab-nav-slot">
<wd-icon name="add-circle1" size="16px"></wd-icon>
</view>
</template>
</wd-tabs>
</demo-block>

<demo-block :title="$t('zai-dan-chu-kuang-zhong-shi-yong-0')" transparent>
<view class="section">
<wd-button @click="handleOpenClick">{{ $t('da-kai-dan-chuang') }}</wd-button>
Expand Down Expand Up @@ -192,6 +212,7 @@ const tab7 = ref<number>(0)
const tab8 = ref<number>(0)
const tab9 = ref<number>(0)
const tab10 = ref<number>(3)
const tab12 = ref<number>(0)

const toast = useToast()
function handleClick({ index, name }: any) {
Expand Down Expand Up @@ -237,4 +258,12 @@ function handlePopupShow() {
justify-content: center;
padding: 24rpx 0;
}
.tab-nav-slot {
align-self: stretch;
padding: 0 8px;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
}
</style>
11 changes: 10 additions & 1 deletion src/uni_modules/wot-design-uni/components/wd-tabs/wd-tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<view class="wd-tabs__nav--wrap">
<scroll-view :scroll-x="innerSlidable" scroll-with-animation :scroll-left="state.scrollLeft">
<view class="wd-tabs__nav-container">
<slot name="nav-left" />
<view
@click="handleSelect(index)"
v-for="(item, index) in children"
Expand All @@ -24,6 +25,7 @@

<view class="wd-tabs__line wd-tabs__line--inner" v-if="state.activeIndex === index && state.useInnerLine"></view>
</view>
<slot name="nav-right" />
<view class="wd-tabs__line" :style="state.lineStyle"></view>
</view>
</scroll-view>
Expand Down Expand Up @@ -80,6 +82,7 @@
<view class="wd-tabs__nav--wrap">
<scroll-view :scroll-x="innerSlidable" scroll-with-animation :scroll-left="state.scrollLeft">
<view class="wd-tabs__nav-container">
<slot name="nav-left" />
<view
v-for="(item, index) in children"
@click="handleSelect(index)"
Expand All @@ -93,6 +96,7 @@
<text v-else class="wd-tabs__nav-item-text">{{ item.title }}</text>
<view class="wd-tabs__line wd-tabs__line--inner" v-if="state.activeIndex === index && state.useInnerLine"></view>
</view>
<slot name="nav-right" />
<view class="wd-tabs__line" :style="state.lineStyle"></view>
</view>
</scroll-view>
Expand Down Expand Up @@ -326,7 +330,12 @@ async function updateLineStyle(animation: boolean = true) {
}
const rects = await getRect($item, true, proxy)
const rect = rects[state.activeIndex]
let left = rects.slice(0, state.activeIndex).reduce((prev, curr) => prev + Number(curr.width), 0) + Number(rect.width) / 2

// 计算激活标签中心点的偏移量: 前面所有标签的宽度 + 第一个标签的左边距 + 当前标签宽度的一半
const previousItemsWidth = rects.slice(0, state.activeIndex).reduce((prev, curr) => prev + Number(curr.width), 0)
const firstItemLeft = rects[0]?.left ?? 0
const left = previousItemsWidth + firstItemLeft + Number(rect.width) / 2

if (left) {
lineStyle.transform = `translateX(${left}px) translateX(-50%)`
if (animation) {
Expand Down
65 changes: 65 additions & 0 deletions tests/components/wd-tabs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,71 @@ describe('WdTabs 和 WdTab 组件', () => {
expect(tabContent.text()).toBe('内容1')
})

/** 验证导航左侧插槽渲染 */
test('自定义导航左侧插槽', async () => {
/** 组件包装器 */
const wrapper = mount(
{
template: `
<wd-tabs v-model="activeTab">
<template #nav-left>
<view class="custom-left">左侧操作</view>
</template>
<wd-tab title="标签1">内容1</wd-tab>
</wd-tabs>
`,
data() {
return {
activeTab: 0
}
}
},
{
global: {
components: globalComponents
}
}
)

await nextTick()

expect(wrapper.find('.custom-left').exists()).toBe(true)
expect(wrapper.find('.custom-left').text()).toBe('左侧操作')
})

/** 验证导航右侧插槽渲染 */
test('自定义导航右侧插槽', async () => {
/** 组件包装器 */
const wrapper = mount(
{
template: `
<wd-tabs v-model="activeTab">
<template #nav-right>
<view class="custom-right">右侧按钮</view>
</template>
<wd-tab title="标签1">内容1</wd-tab>
<wd-tab title="标签2">内容2</wd-tab>
</wd-tabs>
`,
data() {
return {
activeTab: 0
}
}
},
{
global: {
components: globalComponents
}
}
)

await nextTick()

expect(wrapper.find('.custom-right').exists()).toBe(true)
expect(wrapper.find('.custom-right').text()).toBe('右侧按钮')
})

// 测试切换标签页
test('切换标签页', async () => {
const onChange = vi.fn()
Expand Down
Loading