mirror of
https://gitee.com/wot-design-uni/wot-design-uni.git
synced 2025-12-07 17:48:34 +08:00
feat: ✨ 新增 Tabbar 标签栏组件
This commit is contained in:
parent
bc241acfc1
commit
aa0bf19486
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2023-07-27 10:26:09
|
||||
* @LastEditTime: 2023-09-28 11:22:30
|
||||
* @LastEditTime: 2023-10-10 22:42:54
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\docs\.vitepress\config.ts
|
||||
@ -196,6 +196,9 @@ export default defineConfig({
|
||||
}, {
|
||||
link: "/component/segmented",
|
||||
text: "Segmented 分段器"
|
||||
}, {
|
||||
link: "/component/tabbar",
|
||||
text: "Tabbar 标签栏"
|
||||
}]
|
||||
}, {
|
||||
|
||||
|
||||
@ -4,25 +4,180 @@
|
||||
|
||||
底部导航栏,用于在不同页面之间进行切换。
|
||||
|
||||
## 基础用法
|
||||
|
||||
`v-model` 为绑定值,表示选中标签的索引值或者名称。
|
||||
|
||||
```html
|
||||
<wd-tabbar v-model="tabbar1">
|
||||
<wd-tabbar-item title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item title="我的" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { ref } from 'vue'
|
||||
|
||||
const tabbar1 = ref('home')
|
||||
```
|
||||
|
||||
## 通过名称匹配
|
||||
|
||||
通过设置 `name` 属性,可以通过名称匹配选中标签。
|
||||
|
||||
```html
|
||||
<wd-tabbar v-model="tabbar1">
|
||||
<wd-tabbar-item name="home" title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="cart" title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="setting" title="设置" icon="setting"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="user" title="我的" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
## 徽标提示
|
||||
|
||||
通过设置 `value` 属性,可以显示徽标提示,而设置 is-dot 属性后,会在图标右上角展示一个小红点。
|
||||
|
||||
```html
|
||||
<wd-tabbar v-model="tabbar5">
|
||||
<wd-tabbar-item name="1" is-dot :value="2" title="点状" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" :value="2" icon="cart" title="分类"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" :value="30" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" :value="200" title="最大值" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
## 悬浮标签栏
|
||||
|
||||
通过设置 `shape` 属性为 `round`,可以将标签栏设置为悬浮样式。
|
||||
|
||||
```html
|
||||
<wd-tabbar shape="round" v-model="tabbar2">
|
||||
<wd-tabbar-item name="1" title="首页" is-dot :value="2" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" title="分类" :value="2" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" title="相册" :value="30" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" title="我的" :value="200" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
## 自定义图标
|
||||
|
||||
通过使用 `<template #icon>` 可以自定义标签页的图标。
|
||||
|
||||
```html
|
||||
<wd-tabbar v-model="tabbar4">
|
||||
<wd-tabbar-item name="1" :value="2" title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" :value="2" icon="cart" title="分类">
|
||||
<template #icon>
|
||||
<wd-img round height="40rpx" width="40rpx" src="https://unpkg.com/wot-design-uni-assets/panda.jpg"></wd-img>
|
||||
</template>
|
||||
</wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" :value="3" title="我的" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
## 自定义颜色
|
||||
|
||||
通过设置 `active-color` 和 `inactive-color` 属性,可以自定义激活和未激活标签的颜色。
|
||||
|
||||
```html
|
||||
<wd-tabbar v-model="tabbar5" active-color="#ee0a24" inactive-color="#7d7e80">
|
||||
<wd-tabbar-item name="1" is-dot :value="2" title="点状" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" :value="2" icon="cart" title="分类"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" :value="30" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" :value="200" title="最大值" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="5" :value="10" title="客服" icon="chat"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
## 监听切换事件
|
||||
|
||||
通过监听 `change` 事件,可以获取选中标签的值。
|
||||
|
||||
```html
|
||||
<wd-tabbar v-model="tabbar6" @change="handleChange1" active-color="#ee0a24" inactive-color="#7d7e80">
|
||||
<wd-tabbar-item name="1" title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" title="相册" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="5" title="客服" icon="chat"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
```typescript
|
||||
function handleChange1({ value }: { value: string }) {
|
||||
show(`选中标签:${value}`)
|
||||
}
|
||||
```
|
||||
|
||||
## 固定底部
|
||||
|
||||
通过设置 `fixed` 属性,可以将标签栏固定在底部;通过设置 `placeholder` 属性,可以在固定在底部时在标签位置生成一个等高的占位元素。
|
||||
|
||||
```html
|
||||
<wd-tabbar fixed v-model="tabbar3" bordered safeAreaInsetBottom placeholder>
|
||||
<wd-tabbar-item name="1" :value="2" is-dot title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" :value="200" title="相册" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="5" :value="10" title="客服" icon="chat"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
```
|
||||
|
||||
|
||||
## Attributes
|
||||
|
||||
## Tabbar Attributes
|
||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
|
||||
|-----------------------|--------------------------------------------|-----------------------------|--------------------------------------|-------------------|------------|
|
||||
| v-model/modelValue | 选中标签的索引值或者名称 | number / string | - | 0 | 0.1.27 |
|
||||
| fixed | 是否固定在底部 | boolean | - | false | 0.1.27 |
|
||||
| safeAreaInsetBottom | 是否设置底部安全距离(iPhone X 类型的机型) | boolean | - | - | 0.1.27 |
|
||||
| safeAreaInsetBottom | 是否设置底部安全距离(iPhone X 类型的机型) | boolean | - | false | 0.1.27 |
|
||||
| bordered | 是否显示顶部边框 | boolean | - | true | 0.1.27 |
|
||||
| shape | 标签栏的形状 | TabbarShape | 'default' / 'round' | 'default' | 0.1.27 |
|
||||
| activeColor | 激活标签的颜色 | string | - | '' | 0.1.27 |
|
||||
| inactiveColor | 未激活标签的颜色 | string | - | '' | 0.1.27 |
|
||||
| activeColor | 激活标签的颜色 | string | - | - | 0.1.27 |
|
||||
| inactiveColor | 未激活标签的颜色 | string | - | - | 0.1.27 |
|
||||
| placeholder | 固定在底部时,是否在标签位置生成一个等高的占位元素 | boolean | - | false | 0.1.27 |
|
||||
| zIndex | tabbar组件的层级 | number | - | 500 | 0.1.27 |
|
||||
|
||||
## 外部样式类
|
||||
## Tabbar Events
|
||||
|
||||
| 事件名称 | 说明 | 参数 | 最低版本 |
|
||||
| -------- | -------------------------- | ----------- | -------- |
|
||||
| change | tabbar标签切换时触发 | `{ value }` | 0.1.27 |
|
||||
|
||||
|
||||
|
||||
|
||||
## Tabbar 外部样式类
|
||||
|
||||
| 类名 | 说明 | 最低版本 |
|
||||
|-----|-----|---------|
|
||||
| custom-class | 根节点样式类 | - |
|
||||
| custom-style | 根节点样式 | - |
|
||||
| custom-class | 根节点样式类 | 0.1.27 |
|
||||
| custom-style | 根节点样式 | 0.1.27 |
|
||||
|
||||
|
||||
|
||||
|
||||
## TabbarItem Attributes
|
||||
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
|
||||
|--------------|----------------|-------------------------|----------------|----------|------------|
|
||||
| title | 标签页的标题 | string | - | - | 0.1.27 |
|
||||
| name | 唯一标识符 | string / number | - | - | 0.1.27 |
|
||||
| icon | 图标 | string | - | - | 0.1.27 |
|
||||
| value | 徽标显示值 | number / string | - | - | 0.1.27 |
|
||||
| isDot | 是否点状徽标 | boolean | - | false | 0.1.27 |
|
||||
| max | 徽标最大值 | number | - | 99 | 0.1.27 |
|
||||
|
||||
## TabbarItem Slots
|
||||
| name | 说明 | 参数 | 最低版本 |
|
||||
| ------ | -------------------- | ----------------------- | -------- |
|
||||
| icon | 自定义图标 | `active: boolean` | 0.1.27 |
|
||||
|
||||
|
||||
## TabbarItem 外部样式类
|
||||
|
||||
| 类名 | 说明 | 最低版本 |
|
||||
|-----|-----|---------|
|
||||
| custom-class | 根节点样式类 | 0.1.27 |
|
||||
| custom-style | 根节点样式 | 0.1.27 |
|
||||
|
||||
@ -591,6 +591,16 @@
|
||||
},
|
||||
"navigationBarTitleText": "Segmented 分段器"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/tabbar/Index",
|
||||
"name": "tabbar",
|
||||
"style": {
|
||||
"mp-alipay": {
|
||||
"allowsBounceVertical": "NO"
|
||||
},
|
||||
"navigationBarTitleText": "Tabbar 标签栏"
|
||||
}
|
||||
}
|
||||
],
|
||||
// "tabBar": {
|
||||
|
||||
@ -98,6 +98,10 @@ const list = ref([
|
||||
{
|
||||
id: 'segmented',
|
||||
name: 'Segmented 分段器'
|
||||
},
|
||||
{
|
||||
id: 'tabbar',
|
||||
name: 'Tabbar 标签栏'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@ -93,11 +93,11 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
const swiperList = ref([
|
||||
'https://cdn.jsdelivr.net/npm/wot-design-uni-assets/redpanda.jpg',
|
||||
'https://cdn.jsdelivr.net/npm/wot-design-uni-assets/capybara.jpg',
|
||||
'https://cdn.jsdelivr.net/npm/wot-design-uni-assets/panda.jpg',
|
||||
'https://unpkg.com/wot-design-uni-assets/redpanda.jpg',
|
||||
'https://unpkg.com/wot-design-uni-assets/capybara.jpg',
|
||||
'https://unpkg.com/wot-design-uni-assets/panda.jpg',
|
||||
'https://img.yzcdn.cn/vant/cat.jpeg',
|
||||
'https://cdn.jsdelivr.net/npm/wot-design-uni-assets/meng.jpg'
|
||||
'https://unpkg.com/wot-design-uni-assets/meng.jpg'
|
||||
])
|
||||
function handleClick(e) {
|
||||
console.log(e)
|
||||
|
||||
103
src/pages/tabbar/Index.vue
Normal file
103
src/pages/tabbar/Index.vue
Normal file
@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<page-wraper>
|
||||
<wd-toast></wd-toast>
|
||||
<demo-block hor="0" title="基础用法" transparent>
|
||||
<wd-tabbar bordered @change="handleChange">
|
||||
<wd-tabbar-item title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item title="我的" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block hor="0" title="通过名称匹配" transparent>
|
||||
<wd-tabbar bordered @change="handleChange" v-model="tabbar1">
|
||||
<wd-tabbar-item name="home" title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="cart" title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="setting" title="设置" icon="setting"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="user" title="我的" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block hor="0" title="徽标提示" transparent>
|
||||
<wd-tabbar v-model="tabbar5" @change="handleChange">
|
||||
<wd-tabbar-item name="1" is-dot :value="2" title="点状" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" :value="2" icon="cart" title="分类"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" :value="30" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" :value="200" title="最大值" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
<demo-block hor="0" title="悬浮标签栏" transparent>
|
||||
<wd-tabbar shape="round" v-model="tabbar2" @change="handleChange">
|
||||
<wd-tabbar-item name="1" title="首页" is-dot :value="2" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" title="分类" :value="2" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" title="相册" :value="30" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" title="我的" :value="200" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block hor="0" title="自定义图标" transparent>
|
||||
<wd-tabbar v-model="tabbar4" @change="handleChange">
|
||||
<wd-tabbar-item name="1" :value="2" title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" :value="2" icon="cart" title="分类">
|
||||
<template #icon>
|
||||
<wd-img round height="40rpx" width="40rpx" src="https://img.yzcdn.cn/vant/cat.jpeg"></wd-img>
|
||||
</template>
|
||||
</wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" :value="3" title="我的" icon="user"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block hor="0" title="自定义颜色" transparent>
|
||||
<wd-tabbar v-model="tabbar5" @change="handleChange" active-color="#ee0a24" inactive-color="#7d7e80">
|
||||
<wd-tabbar-item name="1" is-dot :value="2" title="点状" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" :value="2" icon="cart" title="分类"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" :value="30" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" :value="200" title="最大值" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="5" :value="10" title="客服" icon="chat"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
<demo-block hor="0" title="监听切换事件" transparent>
|
||||
<wd-tabbar v-model="tabbar6" @change="handleChange1" active-color="#ee0a24" inactive-color="#7d7e80">
|
||||
<wd-tabbar-item name="1" title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" title="相册" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="5" title="客服" icon="chat"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
|
||||
<demo-block hor="0" title="固定底部" transparent>
|
||||
<wd-tabbar fixed v-model="tabbar3" @change="handleChange" bordered safeAreaInsetBottom placeholder>
|
||||
<wd-tabbar-item name="1" :value="2" is-dot title="首页" icon="home"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="2" title="分类" icon="cart"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="3" title="我的" icon="user"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="4" :value="200" title="相册" icon="photo"></wd-tabbar-item>
|
||||
<wd-tabbar-item name="5" :value="10" title="客服" icon="chat"></wd-tabbar-item>
|
||||
</wd-tabbar>
|
||||
</demo-block>
|
||||
</page-wraper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useToast } from '@/uni_modules/wot-design-uni'
|
||||
import { ref } from 'vue'
|
||||
const { show } = useToast()
|
||||
const tabbar1 = ref('home')
|
||||
const tabbar2 = ref('2')
|
||||
const tabbar3 = ref('2')
|
||||
const tabbar4 = ref('1')
|
||||
const tabbar5 = ref('1')
|
||||
const tabbar6 = ref('1')
|
||||
|
||||
function handleChange(event: any) {
|
||||
console.log(event)
|
||||
}
|
||||
|
||||
function handleChange1({ value }: { value: string }) {
|
||||
show(`选中标签:${value}`)
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
:deep(.page-wraper) {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
</style>
|
||||
@ -762,8 +762,18 @@ $-swiper-nav-btn-size: var(--wot-swiper-nav-btn-size, 48rpx) !default;
|
||||
|
||||
|
||||
// segmented
|
||||
$-segmented-padding: var(--wot-segmented-padding, 4px) !default; // 分段器padding
|
||||
$-segmented-item-bg-color: var(--wot-segmented-item-bg-color, #eeeeee) !default;
|
||||
$-segmented-item-color: var(--wot-segmented-item-color, rgba(0, 0, 0, 0.85)) !default; // 标题文字颜色
|
||||
$-segmented-item-acitve-bg: var(--wot-segmented-item-acitve-bg, #FFFFFF) !default; // 标题文字颜色
|
||||
$-segmented-item-disabled-color: var(--wot-segmented-item-disabled-color, rgba(0, 0, 0, 0.25)) !default; // 标题文字禁用颜色
|
||||
|
||||
// tabbar
|
||||
$-tabbar-height: var(--wot-tabbar-height, 50px) !default;
|
||||
$-tabbar-box-shadow: var(--wot-tabbar-box-shadow, 0 6px 30px 5px rgba(0, 0, 0, 0.05), 0 16px 24px 2px rgba(0, 0, 0, 0.04), 0 8px 10px -5px rgba(0, 0, 0, 0.08)) !default; // round类型tabbar阴影
|
||||
|
||||
// tabbar-item
|
||||
$-tabbar-item-title-font-size: var(--wot-tabbar-item-title-font-size, 10px) !default; // tabbar选项文字大小
|
||||
$-tabbar-item-title-line-height: var(--wot-tabbar-item-title-line-height, initial) !default; // tabbar选项标题文字行高
|
||||
$-tabbar-inactive-color: var(--wot-tabbar-inactive-color, $-color-title) !default; // 标题文字和图标颜色
|
||||
$-tabbar-active-color: var(--wot-tabbar-active-color, $-color-theme) !default; // 选中文字和图标颜色
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
@import '../common/abstracts/variable';
|
||||
@import '../common/abstracts/mixin';
|
||||
|
||||
.wot-theme-dark {
|
||||
@include b(tabbar-item) {
|
||||
@include e(body) {
|
||||
:deep(){
|
||||
@include when(inactive) {
|
||||
color: $-dark-color-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include b(tabbar-item) {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
@include e(body) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
|
||||
:deep(){
|
||||
@include when(active) {
|
||||
color: $-tabbar-active-color;
|
||||
}
|
||||
|
||||
@include when(inactive) {
|
||||
color: $-tabbar-inactive-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include e(body-title) {
|
||||
font-size: $-tabbar-item-title-font-size;
|
||||
line-height: $-tabbar-item-title-line-height;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 折叠面板子项
|
||||
*/
|
||||
export interface TabbarItem {
|
||||
// 唯一标识
|
||||
name: string
|
||||
}
|
||||
@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<view class="wd-tabbar-item" :style="customStyle" @click="handleClick">
|
||||
<wd-badge :modelValue="value" :isDot="isDot" :max="max" type="danger">
|
||||
<view class="wd-tabbar-item__body">
|
||||
<slot name="icon" :active="active"></slot>
|
||||
<template v-if="!$slots.icon && icon">
|
||||
<wd-icon :name="icon" size="20px" :custom-style="textStyle" :custom-class="active ? 'is-active' : 'is-inactive'"></wd-icon>
|
||||
</template>
|
||||
<text v-if="title" :style="textStyle" :class="`wd-tabbar-item__body-title ${active ? 'is-active' : 'is-inactive'}`">
|
||||
{{ title }}
|
||||
</text>
|
||||
</view>
|
||||
</wd-badge>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-tabbar-item',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { type CSSProperties, computed, inject, onMounted, ref, watch, getCurrentInstance, reactive } from 'vue'
|
||||
import { isDef, objToStyle } from '../common/util'
|
||||
|
||||
interface Props {
|
||||
// 自定义样式类
|
||||
customClass?: string
|
||||
// 自定义样式
|
||||
customStyle?: string
|
||||
// 标签页的标题
|
||||
title?: string
|
||||
// 唯一标识符
|
||||
name?: string | number
|
||||
// 图标
|
||||
icon?: string
|
||||
// 徽标显示值
|
||||
value?: number | string | null
|
||||
// 是否点状徽标
|
||||
isDot?: boolean
|
||||
// 徽标最大值
|
||||
max?: number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
customStyle: '',
|
||||
isDot: false,
|
||||
max: 99
|
||||
})
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
|
||||
const parent = inject<any>('wdtabbar', { value: '' }) // 父组件
|
||||
const active = ref<boolean>(false) // 是否激活
|
||||
const index = ref<number>(0) // 当前tabbar 下标
|
||||
|
||||
const textStyle = computed(() => {
|
||||
const style: CSSProperties = {}
|
||||
if (active.value && parent.activeColor) {
|
||||
style['color'] = parent.activeColor
|
||||
}
|
||||
if (!active.value && parent.inactiveColor) {
|
||||
style['color'] = parent.inactiveColor
|
||||
}
|
||||
return `${objToStyle(style)}`
|
||||
})
|
||||
|
||||
watch(
|
||||
() => parent.modelValue,
|
||||
(newVal: string | number) => {
|
||||
const name = isDef(props.name) ? props.name : index.value
|
||||
if (isDef(newVal)) {
|
||||
if (newVal === name) {
|
||||
active.value = true
|
||||
} else {
|
||||
active.value = false
|
||||
}
|
||||
} else {
|
||||
active.value = false
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
|
||||
/**
|
||||
* 初始化将组件信息注入父组件
|
||||
*/
|
||||
function init() {
|
||||
if (parent.children && isDef(props.name)) {
|
||||
const repeat = checkRepeat(parent.children, props.name, 'name')
|
||||
if (repeat > -1) {
|
||||
throw Error('[wot-design] warning(wd-tabbar-item): name attribute cannot be defined repeatedly')
|
||||
}
|
||||
}
|
||||
parent.setChild && parent.setChild(proxy)
|
||||
index.value = parent.children.indexOf(proxy)
|
||||
updateActive()
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新展开状态
|
||||
*/
|
||||
function updateActive() {
|
||||
if (parent && isDef(parent.modelValue)) {
|
||||
const name = isDef(props.name) ? props.name : index.value
|
||||
if (parent.modelValue === name) {
|
||||
active.value = true
|
||||
} else {
|
||||
active.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否存在重复name属性
|
||||
* @param {Array} currentList
|
||||
* @param {String} checkValue 比较的重复值
|
||||
* @param {String} key 键名
|
||||
*/
|
||||
function checkRepeat(currentList: any[], checkValue: string | number, key: string): number {
|
||||
return currentList.findIndex((item) => item[key] === checkValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击tabbar选项
|
||||
*/
|
||||
function handleClick() {
|
||||
active.value = true
|
||||
const name = isDef(props.name) ? props.name : index.value
|
||||
parent.setChange && parent.setChange({ name })
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
@ -0,0 +1,43 @@
|
||||
@import '../common/abstracts/variable';
|
||||
@import '../common/abstracts/mixin';
|
||||
|
||||
.wot-theme-dark {
|
||||
@include b(tabbar) {
|
||||
background: $-dark-background;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include b(tabbar) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
position: relative;
|
||||
background: $-color-white;
|
||||
height: $-tabbar-height;
|
||||
|
||||
@include m(round){
|
||||
margin-left: 32rpx;
|
||||
margin-right: 32rpx;
|
||||
border-radius: 999px;
|
||||
box-shadow: $-tabbar-box-shadow;
|
||||
}
|
||||
|
||||
@include when(border){
|
||||
@include m(default){
|
||||
@include halfPixelBorder('top');
|
||||
}
|
||||
}
|
||||
|
||||
@include when(fixed) {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 500;
|
||||
@include when(safe) {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<view :style="{ height: addUnit(height) }">
|
||||
<view
|
||||
:class="`wd-tabbar wd-tabbar--${shape} ${customClass} ${fixed ? 'is-fixed' : ''} ${safeAreaInsetBottom ? 'is-safe' : ''} ${
|
||||
bordered ? 'is-border' : ''
|
||||
}`"
|
||||
:style="rootStyle"
|
||||
>
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-tabbar',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { getCurrentInstance, onMounted, provide, reactive, ref, watch, nextTick, computed, type CSSProperties } from 'vue'
|
||||
import { TabbarItem } from '../wd-tabbar-item/types'
|
||||
import { addUnit, getRect, isDef, objToStyle } from '../common/util'
|
||||
|
||||
type TabbarShape = 'default' | 'round'
|
||||
|
||||
interface Props {
|
||||
// 自定义样式类
|
||||
customClass?: string
|
||||
// 自定义样式
|
||||
customStyle?: string
|
||||
// 选中标签的索引值或者名称
|
||||
modelValue?: number | string
|
||||
// 是否固定在底部
|
||||
fixed?: boolean
|
||||
// 是否设置底部安全距离(iphone X 类型的机型)
|
||||
safeAreaInsetBottom?: boolean
|
||||
// 是否显示顶部边框
|
||||
bordered?: boolean
|
||||
// 标签栏的形状。可选项:default/round
|
||||
shape?: TabbarShape
|
||||
// 激活标签的颜色
|
||||
activeColor?: string
|
||||
// 未激活标签的颜色
|
||||
inactiveColor?: string
|
||||
// 固定在底部时,是否在标签位置生成一个等高的占位元素
|
||||
placeholder?: boolean
|
||||
// 自定义组件的层级
|
||||
zIndex?: number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
customClass: '',
|
||||
customStyle: '',
|
||||
modelValue: 0,
|
||||
fixed: false,
|
||||
bordered: true,
|
||||
safeAreaInsetBottom: false,
|
||||
shape: 'default',
|
||||
inactiveColor: '',
|
||||
activeColor: '',
|
||||
placeholder: false,
|
||||
zIndex: 500
|
||||
})
|
||||
const height = ref<number>(50) // 占位高度
|
||||
const parentData = reactive({
|
||||
activeColor: props.activeColor,
|
||||
inactiveColor: props.inactiveColor,
|
||||
modelValue: props.modelValue,
|
||||
children: [] as any[],
|
||||
setChild,
|
||||
setChange
|
||||
})
|
||||
|
||||
const rootStyle = computed(() => {
|
||||
const style: CSSProperties = {}
|
||||
if (isDef(props.zIndex)) {
|
||||
style['z-index'] = props.zIndex
|
||||
}
|
||||
return `${objToStyle(style)};${props.customStyle}`
|
||||
})
|
||||
|
||||
const { proxy } = getCurrentInstance() as any
|
||||
|
||||
provide('wdtabbar', parentData)
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
parentData.modelValue = newValue
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
[() => props.fixed, () => props.placeholder],
|
||||
() => {
|
||||
setPlaceholderHeight()
|
||||
},
|
||||
{ deep: true, immediate: false }
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
if (props.fixed && props.placeholder) {
|
||||
nextTick(() => {
|
||||
setPlaceholderHeight()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['change', 'update:modelValue'])
|
||||
|
||||
/**
|
||||
* 设置子项
|
||||
* @param child
|
||||
*/
|
||||
function setChild(child: any) {
|
||||
const hasChild = parentData.children.indexOf(child)
|
||||
if (hasChild === -1) {
|
||||
parentData.children.push(child)
|
||||
} else {
|
||||
parentData.children[hasChild] = child
|
||||
}
|
||||
if (!isDef(props.modelValue) && parentData.children.length === 1) {
|
||||
const name = isDef(parentData.children[0].name) ? parentData.children[0].name : 0
|
||||
setChange({ name })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 子项状态变更
|
||||
* @param child 子项
|
||||
*/
|
||||
function setChange(child: TabbarItem) {
|
||||
let active = child.name
|
||||
emit('update:modelValue', active)
|
||||
parentData.modelValue = active
|
||||
emit('change', {
|
||||
value: active
|
||||
})
|
||||
}
|
||||
|
||||
function setPlaceholderHeight() {
|
||||
if (!props.fixed || !props.placeholder) {
|
||||
return
|
||||
}
|
||||
|
||||
getRect('.wd-tabbar', false, proxy).then((res: any) => {
|
||||
height.value = res.height
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
2
src/uni_modules/wot-design-uni/global.d.ts
vendored
2
src/uni_modules/wot-design-uni/global.d.ts
vendored
@ -81,6 +81,8 @@ declare module '@vue/runtime-core' {
|
||||
WdSwiper: typeof import('./components/wd-swiper/wd-swiper.vue')['default']
|
||||
WdSwiperNav: typeof import('./components/wd-swiper-nav/wd-swiper-nav.vue')['default']
|
||||
WdSegmented: typeof import('./components/wd-segmented/wd-segmented.vue')['default']
|
||||
WdTabbar: typeof import('./components/wd-tabbar/wd-tabbar.vue')['default']
|
||||
WdTabbarItem: typeof import('./components/wd-tabbar-item/wd-tabbar-item.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user