uni-indexed-list 是 uni-app 的 uni-ui 组件库中的一个索引列表组件,用于创建带有索引栏的列表视图。这种组件通常用于长列表的快速导航,例如联系人列表、城市列表等,用户可以通过点击或滑动索引栏快速跳转到列表的指定部分。
原 uni-indexed-list 只支持特定数据结构:如
html
[{
"letter": "A",
"data": [
"阿克苏机场",
"阿拉山口机场",
"阿勒泰机场",
"阿里昆莎机场",
"安庆天柱山机场",
"澳门国际机场"
]
}, {
"letter": "B",
"data": [
"保山机场",
"包头机场",
"北海福成机场",
"北京南苑机场",
"北京首都国际机场"
]
}]
为了更好的兼容所有格式,现源码修改如下:
javascript
props: {
options: {
type: Array,
default () {
return []
}
},
// 添加属性配置
prop:{
type:Object,
default:{
letter:"letter",
label:"name",
data:"data"
}
},
showSelect: {
type: Boolean,
default: false
}
},
.............
setList() {
let index = 0;
this.lists = []
this.options.forEach((value, index) => {
// 根据prop 配置进行获取数据
const dlst = value[this.prop.data];
if (dlst.length === 0) {
return
}
let indexBefore = index
let items = dlst.map(item => {
let obj = {}
obj['key'] = value[this.prop.letter]
obj['name'] = item[this.prop.label]
obj['data'] = item
obj['itemIndex'] = index
index++
obj.checked = item.checked ? item.checked : false
return obj
})
this.lists.push({
title: value[this.prop.letter],
key: value[this.prop.letter],
items: items,
itemIndex: indexBefore
})
})
具体源码查下载:https://download.csdn.net/download/simayilong/92988910
使用事例代码如下:
html
<template>
<view class="city-container">
<view class="search-box">
<view class="search-input-wrapper">
<icon type="search" size="16" color="#999" />
<input type="text" v-model="searchKeyword" placeholder="输入城市名或拼音" />
</view>
<view class="city_current">
<label @click="handleChangeCity(1)"
:style="{color:province.name?'#F34A33':'#333' }">{{province.name||'请选择省份'}}</label>
<label v-if="type===2" :style="{color:cityArea.name?'#F34A33':'#333' }"> -- {{cityArea.name||"请选择城市"}}</label>
</view>
</view>
<scroll-view class="city-scroll" scroll-y scroll-with-animation>
<uni-indexed-list :options="newCityList" :prop="{label:'name',data:'list'}" :show-select="false"
@click="bindClick">
</uni-indexed-list>
</scroll-view>
</view>
</template>
<script>
/**
* 城市选择组件
* 采用 Vue2 Options API 编写
*/
const cityData=[{"letter":"A","list":[{"code":340000,"name":"安徽省"},{"code":820000,"name":"澳门特别行政区"}]},{"letter":"B","list":[{"code":110000,"name":"北京市"}]},{"letter":"C","list":[{"code":500000,"name":"重庆市"}]},{"letter":"F","list":[{"code":350000,"name":"福建省"}]},{"letter":"G","list":[{"code":440000,"name":"广东省"},{"code":450000,"name":"广西壮族自治区"},{"code":520000,"name":"贵州省"},{"code":620000,"name":"甘肃省"}]},{"letter":"H","list":[{"code":130000,"name":"河北省"},{"code":230000,"name":"黑龙江省"},{"code":410000,"name":"河南省"},{"code":420000,"name":"湖北省"},{"code":430000,"name":"湖南省"},{"code":460000,"name":"海南省"}]},{"letter":"J","list":[{"code":220000,"name":"吉林省"},{"code":320000,"name":"江苏省"},{"code":360000,"name":"江西省"}]},{"letter":"L","list":[{"code":210000,"name":"辽宁省"}]},{"letter":"N","list":[{"code":150000,"name":"内蒙古自治区"},{"code":640000,"name":"宁夏回族自治区"}]},{"letter":"Q","list":[{"code":630000,"name":"青海省"}]},{"letter":"S","list":[{"code":140000,"name":"山西省"},{"code":310000,"name":"上海市"},{"code":370000,"name":"山东省"},{"code":510000,"name":"四川省"},{"code":610000,"name":"陕西省"}]},{"letter":"T","list":[{"code":120000,"name":"天津市"},{"code":710000,"name":"台湾省"}]},{"letter":"X","list":[{"code":540000,"name":"西藏自治区"},{"code":650000,"name":"新疆维吾尔自治区"},{"code":810000,"name":"香港特别行政区"}]},{"letter":"Y","list":[{"code":530000,"name":"云南省"}]},{"letter":"Z","list":[{"code":330000,"name":"浙江省"}]}]
export default {
data() {
return {
searchKeyword: '',
cityList: [],
type: 1,
cityCode: "",
province: "",
cityArea: ""
};
},
onLoad() {
this.getCityList(this.type, this.code)
},
computed: {
// 过滤城市数据省市区数据
newCityList() {
if (this.searchKeyword) {
//根据关键字过滤省份数据,搜索关键字(支持 name、code 或 letter)
const kw = String(this.searchKeyword).trim().toLowerCase();
return this.cityList.reduce((result, group) => {
// letter 精确匹配
if (group.letter.toLowerCase() === kw) {
result.push({ letter: group.letter, list: [...group.list] });
return result;
}
// code / name 模糊匹配 过滤 list
const filtered = group.list.filter(item =>
String(item.code).includes(kw) || item.name.includes(this.searchKeyword.trim())
);
if (filtered.length > 0) {
result.push({ letter: group.letter, list: filtered });
}
return result;
}, []);
}
return this.cityList
}
},
onShow() {
},
methods: {
getCityList(type = 1, code = "") {
// TODO 获取城市列表,api接口待定
this.cityList = cityData
},
bindClick(e) {
console.log('点击item,返回数据' + JSON.stringify(e))
this.handleSelectCity(e.item.data)
},
// 切换省份
handleChangeCity(type) {
this.type = 1
this.province.name=""
this.province.code=""
this.getCityList(this.type, "")
this.cityArea = {}
},
/**
* 选中城市返回
* @param {String} name 城市名称
*/
handleSelectCity(item) {
console.log('用户选择了城市:', item);
if (this.type === 1) {
this.searchKeyword=""
this.province = item
this.type = 2
this.getCityList(this.type, item.code)
} else if (this.type === 2) {
this.cityArea = item
// 返回上一页,并带上数据 省、市、区
uni.$emit("handle-city", {
name: `${this.province.name}-${this.cityArea.name}`,
code: `${this.province.code}-${this.cityArea.code}`
})
uni.navigateBack()
}
}
}
};
</script>
<style scoped>
.city-container {
/* display: flex;
flex-direction: column; */
width: 100%;
height: 100%;
background-color: #f7f7f7;
}
/* 搜索框样式 */
.search-box {
padding: 20rpx 30rpx;
background-color: #ffffff;
}
.search-input-wrapper {
display: flex;
align-items: center;
background-color: #f2f2f2;
height: 72rpx;
padding: 0 20rpx;
border-radius: 36rpx;
}
.search-input-wrapper input {
flex: 1;
margin-left: 10rpx;
font-size: 28rpx;
}
.city_current {
border-bottom: 1rpx solid #E6E6E6;
padding: 20rpx 10rpx;
font-weight: 500;
font-size: 28rpx;
color: #F34A33;
text-align: left;
}
/* 滚动区样式 */
.city-scroll {
flex: 1;
overflow: hidden;
height: calc(90vh - 80px);
}
.section {
padding: 20rpx 30rpx;
}
.section-title {
font-size: 26rpx;
color: #999;
margin-bottom: 20rpx;
}
/* 标签样式(定位和热门) */
.city-tags {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.tag-item {
background-color: #ffffff;
width: 200rpx;
height: 70rpx;
line-height: 70rpx;
text-align: center;
border-radius: 8rpx;
font-size: 28rpx;
color: #333;
border: 1rpx solid #eee;
}
/* 字母分组样式 */
.group-title {
background-color: #f0f0f0;
padding: 10rpx 30rpx;
font-size: 24rpx;
color: #666;
}
.city-item {
padding: 30rpx;
background-color: #ffffff;
border-bottom: 1rpx solid #f0f0f0;
font-size: 30rpx;
color: #333;
}
/* 侧边索引条 */
.index-bar {
position: fixed;
right: 10rpx;
top: 55%;
transform: translateY(-50%);
display: flex;
flex-direction: column;
align-items: center;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 20rpx;
padding: 10rpx 5rpx;
box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
}
.index-item {
font-size: 22rpx;
color: #F34A33;
padding: 6rpx 10rpx;
font-weight: bold;
}
</style>