Skip to content

Commit f84e9af

Browse files
authored
feat: ✨ 添加索引栏组件 (#321)
* feat: ✨ 添加索引栏组件 * refactor: 使用getRect替换uni.createSelectorQuery
1 parent 7544d69 commit f84e9af

File tree

13 files changed

+478
-0
lines changed

13 files changed

+478
-0
lines changed

docs/.vitepress/config.mts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ export default defineConfig({
250250
}, {
251251
link: "/component/backtop",
252252
text: "Backtop 回到顶部"
253+
}, {
254+
link: "/component/indexBar",
255+
text: "IndexBar 索引栏"
253256
}]
254257
}, {
255258

docs/component/indexBar.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<frame/>
2+
3+
# IndexBar 索引栏 `$LOWEST_VERSION$`
4+
5+
用于列表的索引分类显示和快速定位。
6+
7+
## 基本用法
8+
9+
使用一个固定高度的元素包裹`wd-index-bar`组件,组件的宽高会和包裹元素相同。
10+
11+
`wd-index-anchor`作为子组件使用,会根据anchor组件的`index`属性生成锚点以及侧边栏。
12+
13+
```vue
14+
<template>
15+
<view class="wrap" :style="{ height: wrapHeight + 'px' }">
16+
<wd-index-bar>
17+
<view v-for="item in data" :key="item.index" class="city-wrap">
18+
<wd-index-anchor :index="item.index" />
19+
<view v-for="city in item.data" class="city" :key="city">{{ city }}</view>
20+
</view>
21+
</wd-index-bar>
22+
</view>
23+
</template>
24+
25+
26+
<script lang="ts" setup>
27+
import { ref } from 'vue';
28+
import { onMounted } from 'vue';
29+
30+
const wrapHeight = ref(400)
31+
32+
onMounted(() => {
33+
const info = uni.getWindowInfo()
34+
wrapHeight.value = info.windowHeight
35+
})
36+
37+
const data = ref([
38+
{
39+
index: 'A',
40+
data: ["阿坝", "阿拉善", "阿里", "安康", "安庆", "鞍山", "安顺", "安阳", "澳门",]
41+
},
42+
{
43+
index: 'B',
44+
data: ["北京", "白银", "保定", "宝鸡", "保山", "包头", "巴中", "北海", "蚌埠", "本溪", "毕节", "滨州", "百色", "亳州"]
45+
},
46+
{
47+
index: 'C',
48+
data: ["重庆", "成都", "长沙", "长春", "沧州", "常德", "昌都", "长治", "常州", "巢湖", "潮州", "承德", "郴州", "赤峰", "池州", "崇左", "楚雄", "滁州", "朝阳"]
49+
},
50+
{
51+
index: 'D',
52+
data: ["大连", "东莞", "大理", "丹东", "大庆", "大同", "大兴安岭", "德宏", "德阳", "德州", "定西", "迪庆", "东营"]
53+
},
54+
{
55+
index: 'E',
56+
data: ["鄂尔多斯", "恩施", "鄂州"]
57+
},
58+
{
59+
index: 'F',
60+
data: ["福州", "防城港", "佛山", "抚顺", "抚州", "阜新", "阜阳"]
61+
},
62+
{
63+
index: 'G',
64+
data: ["广州", "桂林", "贵阳", "甘南", "赣州", "甘孜", "广安", "广元", "贵港", "果洛"]
65+
},
66+
{
67+
index: 'H',
68+
data: ["杭州", "哈尔滨", "合肥", "海口", "呼和浩特", "海北", "海东", "海南", "海西", "邯郸", "汉中", "鹤壁", "河池", "鹤岗", "黑河", "衡水", "衡阳", "河源", "贺州", "红河", "淮安", "淮北", "怀化", "淮南", "黄冈", "黄南", "黄山", "黄石", "惠州", "葫芦岛", "呼伦贝尔", "湖州", "菏泽"]
69+
}
70+
])
71+
</script>
72+
73+
<style lang="scss">
74+
.city {
75+
padding: 20px;
76+
font-size: 14px;
77+
color: black;
78+
border-bottom: 1px solid #ddd;
79+
}
80+
81+
.city-wrap .city:last-child {
82+
margin-bottom: 10px;
83+
}
84+
85+
.wot-theme-dark {
86+
.city {
87+
color: white;
88+
border-bottom-color: #666;
89+
}
90+
}
91+
</style>
92+
```
93+
94+
## IndexAnchor Attributes
95+
96+
| 参数 | 说明 | 类型 | 可选值 | 默认值 | 最低版本 |
97+
| ----- | -------- | ---------------- | ------ | ------ | -------- |
98+
| index | 索引字符 | string \| number | - | - | - |
99+
100+
## IndexAnchor Slots
101+
102+
| name | 说明 | 参数 | 最低版本 |
103+
| ------- | ---------- | ---- | -------- |
104+
| default | 自定义内容 | - | - |
105+
106+
## IndexAnchor 外部样式类
107+
108+
| 类名 | 说明 | 最低版本 |
109+
| ----------- | ------------ | -------- |
110+
| customStyle | 自定义样式 | - |
111+
| customClass | 自定义样式类 | - |

src/pages.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,16 @@
771771
},
772772
"navigationBarTitleText": "Backtop 回到顶部"
773773
}
774+
},
775+
{
776+
"path": "pages/indexBar/Index",
777+
"name": "indexBar",
778+
"style": {
779+
"mp-alipay": {
780+
"allowsBounceVertical": "NO"
781+
},
782+
"navigationBarTitleText": "IndexBar 索引栏"
783+
}
774784
}
775785
],
776786
// "tabBar": {

src/pages/index/Index.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ const list = ref([
121121
{
122122
id: 'backtop',
123123
name: 'Backtop 回到顶部'
124+
},
125+
{
126+
id: 'indexBar',
127+
name: 'IndexBar 索引栏'
124128
}
125129
]
126130
},

src/pages/indexBar/Index.vue

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<template>
2+
<page-wraper>
3+
<view class="wrap" :style="{ height: wrapHeight + 'px' }">
4+
<wd-index-bar>
5+
<view v-for="item in data" :key="item.index" class="city-wrap">
6+
<wd-index-anchor :index="item.index" />
7+
<view v-for="city in item.data" class="city" :key="city">{{ city }}</view>
8+
</view>
9+
</wd-index-bar>
10+
</view>
11+
</page-wraper>
12+
</template>
13+
14+
<script lang="ts" setup>
15+
import { ref } from 'vue'
16+
import { onMounted } from 'vue'
17+
18+
const wrapHeight = ref(400)
19+
20+
onMounted(() => {
21+
const info = uni.getWindowInfo()
22+
wrapHeight.value = info.windowHeight
23+
})
24+
25+
const data = ref([
26+
{
27+
index: 'A',
28+
data: ['阿坝', '阿拉善', '阿里', '安康', '安庆', '鞍山', '安顺', '安阳', '澳门']
29+
},
30+
{
31+
index: 'B',
32+
data: ['北京', '白银', '保定', '宝鸡', '保山', '包头', '巴中', '北海', '蚌埠', '本溪', '毕节', '滨州', '百色', '亳州']
33+
},
34+
{
35+
index: 'C',
36+
data: [
37+
'重庆',
38+
'成都',
39+
'长沙',
40+
'长春',
41+
'沧州',
42+
'常德',
43+
'昌都',
44+
'长治',
45+
'常州',
46+
'巢湖',
47+
'潮州',
48+
'承德',
49+
'郴州',
50+
'赤峰',
51+
'池州',
52+
'崇左',
53+
'楚雄',
54+
'滁州',
55+
'朝阳'
56+
]
57+
},
58+
{
59+
index: 'D',
60+
data: ['大连', '东莞', '大理', '丹东', '大庆', '大同', '大兴安岭', '德宏', '德阳', '德州', '定西', '迪庆', '东营']
61+
},
62+
{
63+
index: 'E',
64+
data: ['鄂尔多斯', '恩施', '鄂州']
65+
},
66+
{
67+
index: 'F',
68+
data: ['福州', '防城港', '佛山', '抚顺', '抚州', '阜新', '阜阳']
69+
},
70+
{
71+
index: 'G',
72+
data: ['广州', '桂林', '贵阳', '甘南', '赣州', '甘孜', '广安', '广元', '贵港', '果洛']
73+
},
74+
{
75+
index: 'H',
76+
data: [
77+
'杭州',
78+
'哈尔滨',
79+
'合肥',
80+
'海口',
81+
'呼和浩特',
82+
'海北',
83+
'海东',
84+
'海南',
85+
'海西',
86+
'邯郸',
87+
'汉中',
88+
'鹤壁',
89+
'河池',
90+
'鹤岗',
91+
'黑河',
92+
'衡水',
93+
'衡阳',
94+
'河源',
95+
'贺州',
96+
'红河',
97+
'淮安',
98+
'淮北',
99+
'怀化',
100+
'淮南',
101+
'黄冈',
102+
'黄南',
103+
'黄山',
104+
'黄石',
105+
'惠州',
106+
'葫芦岛',
107+
'呼伦贝尔',
108+
'湖州',
109+
'菏泽'
110+
]
111+
}
112+
])
113+
</script>
114+
115+
<style lang="scss">
116+
.city {
117+
padding: 20px;
118+
font-size: 14px;
119+
color: black;
120+
border-bottom: 1px solid #ddd;
121+
}
122+
123+
.city-wrap .city:last-child {
124+
margin-bottom: 10px;
125+
}
126+
127+
.wot-theme-dark {
128+
.city {
129+
color: white;
130+
border-bottom-color: #666;
131+
}
132+
}
133+
</style>

src/uni_modules/wot-design-uni/components/common/abstracts/variable.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,3 +872,6 @@ $-form-item-error-message-line-height: var(--wot-form-item-error-message-line-he
872872

873873
/* backtop */
874874
$-backtop-bg: var(--wot-backtop-bg, #e1e1e1) !default;
875+
876+
/* index-bar */
877+
$-index-bar-index-font-size: var(--wot-index-bar-index-font-size, $-fs-aid) !default;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
@import "./../common/abstracts/_mixin.scss";
2+
@import "./../common/abstracts/variable.scss";
3+
4+
.wot-theme-dark {
5+
@include b(index-anchor) {
6+
background-color: $-color-gray-8;
7+
color: $-color-white;
8+
}
9+
}
10+
11+
@include b(index-anchor) {
12+
background-color: $-color-gray-3;
13+
padding: 10px;
14+
font-size: 14px;
15+
color: $-color-title;
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type { ExtractPropTypes } from 'vue'
2+
import { baseProps, makeRequiredProp } from '../common/props'
3+
4+
export const indexAnchorProps = {
5+
...baseProps,
6+
index: makeRequiredProp([String, Number])
7+
}
8+
9+
export type IndexAnchorProps = ExtractPropTypes<typeof indexAnchorProps>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<template>
2+
<view class="wd-index-anchor" :class="customClass" :style="customStyle">
3+
<slot>
4+
{{ index }}
5+
</slot>
6+
</view>
7+
</template>
8+
9+
<script setup lang="ts">
10+
import { indexAnchorProps } from './type'
11+
import { onMounted, getCurrentInstance, inject } from 'vue'
12+
import { indexBarInjectionKey } from '../wd-index-bar/type'
13+
import { getRect } from '../common/util'
14+
15+
const props = defineProps(indexAnchorProps)
16+
17+
const indexBar = inject(indexBarInjectionKey)!
18+
19+
const { proxy } = getCurrentInstance()!
20+
21+
function getInfo() {
22+
getRect('.wd-index-anchor', false, proxy).then((res) => {
23+
const anchor = indexBar.anchorList.value.find((v) => v.index === props.index)!
24+
anchor.top = res.top!
25+
})
26+
}
27+
28+
onMounted(() => {
29+
indexBar.anchorList.value.push({ top: 0, index: props.index })
30+
getInfo()
31+
})
32+
</script>
33+
34+
<style lang="scss" scoped>
35+
@import './index.scss';
36+
</style>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
@import "./../common/abstracts/_mixin.scss";
2+
@import "./../common/abstracts/variable.scss";
3+
4+
.wot-theme-dark {
5+
@include b(index-bar) {
6+
@include e(index) {
7+
color: $-color-white;
8+
}
9+
}
10+
}
11+
12+
@include b(index-bar) {
13+
position: relative;
14+
width: 100%;
15+
height: 100%;
16+
17+
@include e(content) {
18+
width: 100%;
19+
height: 100%;
20+
}
21+
22+
@include e(sidebar) {
23+
position: absolute;
24+
top: 50%;
25+
right: 4px;
26+
transform: translateY(-50%);
27+
}
28+
29+
@include e(index) {
30+
font-size: 12px;
31+
font-weight: $-fw-medium;
32+
color: $-color-title;
33+
padding: 4px 6px;
34+
35+
@include when(active) {
36+
color: $-color-theme;
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)