1. 组件概述
城市选择组件是一个基于 uni-app 框架开发的移动端城市选择页面,提供城市搜索、热门城市快速选择、字母索引定位等功能,为用户提供便捷的城市选择体验。
2. 功能特性
| 特性 | 描述 |
|---|---|
| 🔍 城市搜索 | 支持按城市名称、拼音、首字母三种方式搜索 |
| ⭐ 热门城市 | 展示热门城市快捷选择入口 |
| 📚 字母索引 | 右侧字母索引栏,点击快速定位到对应字母区域 |
| 🎯 定位模拟 | 模拟定位功能,一键获取当前城市 |
| ✨ 选中高亮 | 选中城市名称高亮显示,提升用户体验 |
| 📱 响应式设计 | 适配多种移动端屏幕尺寸 |
3. 技术栈
- 框架: uni-app (Vue 3 + TypeScript)
- 组件库: uView Plus
- 样式: SCSS
- 开发工具: HBuilderX
4. 项目结构
CityList_Demo/
├── pages/
│ └── index/
│ └── index.vue # 城市选择主页面
├── utils/
│ └── cities.js # 城市数据(热门城市、字母分组城市、字母列表)
├── uni_modules/
│ └── uview-plus/ # uView Plus 组件库
├── App.vue # 应用入口组件
├── main.js # 应用入口文件
├── manifest.json # 应用配置
├── pages.json # 页面路由配置
└── uni.scss # 全局样式变量
5. 核心功能实现
5.1 数据结构
城市数据接口定义(CityItem):
| 字段 | 类型 | 描述 |
|---|---|---|
value | string | 城市编码(如:110100 代表北京) |
label | string | 城市名称(如:北京市) |
pinyin | string | 城市拼音(用于拼音搜索) |
5.2 响应式状态
| 状态变量 | 类型 | 初始值 | 说明 |
|---|---|---|---|
keyword | ref<string> | '' | 搜索关键词 |
selectedCity | ref<string> | '' | 用户选中的城市名称 |
currentCity | ref<string> | '武汉市' | 当前定位城市 |
currentLetter | ref<string> | '' | 当前点击的字母索引 |
showLetterTip | ref<boolean> | false | 是否显示字母提示弹窗 |
scrollToView | ref<string> | '' | 滚动目标ID |
5.3 核心函数
| 函数名 | 功能说明 | 参数 | 返回值 |
|---|---|---|---|
handleSearch(val) | 搜索事件处理 | val: 搜索关键词 | 无 |
scrollToLetter(letter) | 点击字母索引滚动到对应区域 | letter: 目标字母 | 无 |
selectCity(city) | 选择城市处理 | city: 城市对象 | 无 |
refreshLocation() | 模拟刷新定位 | 无 | 无 |
onScroll() | 滚动事件处理(预留) | 无 | 无 |
5.4 计算属性
| 属性名 | 功能说明 | 返回值 |
|---|---|---|
showSearchResult | 判断是否显示搜索结果 | boolean |
searchList | 热门城市搜索结果 | Array |
searchResult | 完整城市搜索结果(支持名称、拼音、首字母搜索) | CityItem[] |
6. 搜索算法说明
搜索功能支持三种匹配方式:
const searchResult = computed(() => {
const keyword = keyword.value.toLowerCase().trim()
if (!keyword) return []
const results: CityItem[] = []
for (const group of cityData) {
for (const city of group.cities) {
// 名称匹配
const labelMatch = city.label.includes(keyword)
// 拼音匹配
const pinyinMatch = city.pinyin && city.pinyin.includes(keyword)
// 首字母匹配
const firstLetterMatch = city.label.charAt(0).toLowerCase() === keyword
if (labelMatch || pinyinMatch || firstLetterMatch) {
results.push(city)
}
}
}
return results.slice(0, 20) // 最多返回20条结果
})
7. 字母索引滚动机制
点击右侧字母索引栏时,通过 scroll-view 的 scroll-into-view 属性实现滚动定位:
const scrollToLetter = (letter: string) => {
currentLetter.value = letter
showLetterTip.value = true
scrollToView.value = ''
setTimeout(() => {
scrollToView.value = 'city-group-' + letter
}, 50)
setTimeout(() => {
showLetterTip.value = false
}, 500)
}
实现原理:
- 更新当前字母状态并显示提示弹窗
- 先清空滚动目标(触发重新滚动)
- 50ms 后设置滚动目标为对应字母区域的 ID
- 500ms 后隐藏字母提示弹窗
8. 样式结构
8.1 布局架构
![```
┌─────────────────────────────────────────────────────┐
│ ┌─────────────────────────────────────────────┐ │
│ │ 搜索栏 (search-bar) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ 当前城市: 武汉市 [刷新定位] │ │
│ │ (city-top-bar) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────┐ ┌───────┐ │
│ │ [搜索结果区域 / 城市列表区域] │ │ A │ │
│ │ • 热门城市 │ │ B │ │
│ │ 北京 | 上海 | 广州 | ... │ │ C │ │
│ │ • 字母分组 │ │ ... │ │
│ │ A │ │ Z │ │
│ │ 阿坝藏族羌族自治州 │ └───────┘ │
│ │ 安康市 │ │
│ │ B │ │
│ │ 蚌埠市 │ │
│ │ ... │ │
│ └─────────────────────────────────────┘ │
│ │
│ [字母提示弹窗: 居中显示当前字母] │
└─────────────────────────────────────────────────────┘](https://i-blog.csdnimg.cn/direct/c61571a903f84c2caf9e237c5e672695.png)
### 8.2 样式类说明
| 样式类 | 说明 | 关键属性 |
|--------|------|----------|
| `.content` | 主容器 | 背景色 `#f5f5f5` |
| `.search-bar` | 搜索栏容器 | 内边距 `20rpx` |
| `.city-top-bar` | 顶部栏 | flex布局,两端对齐 |
| `.city-scroll` | 滚动容器 | 固定定位,占满剩余空间 |
| `.city-group-title` | 字母分组标题 | 背景色 `#F5F5F5`,灰色文字 |
| `.city-item` | 城市列表项 | 白色背景,底部边框 |
| `.check-icon-blue` | 选中勾选图标 | 蓝色 `#007AFF` |
| `.city-name-highlight` | 选中城市高亮 | 蓝色 `#007AFF`,加粗 |
| `.letter-index` | 字母索引栏 | 固定定位右侧,垂直排列 |
| `.letter-item` | 字母索引项 | 灰色文字,激活时变蓝 |
| `.letter-tip` | 字母提示弹窗 | 半透明背景,居中显示 |
## 9. 使用示例
### 9.1 页面路由配置
在 `pages.json` 中配置页面路由:
```json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "选择城市"
}
}
]
}
9.2 组件集成
在其他页面跳转至城市选择页面:
// 跳转至城市选择页面
uni.navigateTo({
url: '/pages/index/index'
})
9.3 数据交互
城市选择后可通过状态管理或事件传递选中的城市信息:
const selectCity = (city: CityItem) => {
selectedCity.value = city.label
currentCity.value = city.label
// 可在此处通过 uni.$emit 或状态管理传递数据
// uni.$emit('citySelected', city)
uni.showToast({
title: '已选择:' + city.label,
icon: 'none'
})
}
10. 兼容性说明
| 平台 | 支持状态 | 说明 |
|---|---|---|
| 微信小程序 | ✅ 支持 | 完全兼容 |
| 支付宝小程序 | ✅ 支持 | 完全兼容 |
| H5 | ✅ 支持 | 完全兼容 |
| App | ✅ 支持 | 完全兼容 |
8688

被折叠的 条评论
为什么被折叠?



