后台-选择城市-简历

该代码实现了一个Vue组件,功能包括:通过拼音首字母搜索城市,从API获取并缓存城市数据,展示分组城市列表,支持弹窗的打开和关闭,以及选中城市后向父组件发送事件。
摘要由CSDN通过智能技术生成
<script setup lang="ts">
	import { ref } from 'vue'
	import { searchCityBySpell } from '@/api/system/region'
	import { RegionDataResult } from '@/types/api/system/region'

	const emit = defineEmits(['selectCity'])
	// 弹窗显示
	const visible = ref(false)

	// 打开弹框
	const openDialog = () => {
		visible.value = true
		searchCity(selectedGroup.value)
	}
	// 关闭弹框
	const closeDialog = () => {
		visible.value = false
	}
	// 暴露方法给父组件
	defineExpose({
		openDialog,
	})

	// 等待进度
	const loading = ref(true)
	// 城市分组数据
	const cityGroupData = ref<Map<string, RegionDataResult | undefined>>()
	// 城市数据
	const cityData = ref<RegionDataResult>()
	// 初始化城市分组
	const initCityGroupData = () => {
		cityGroupData.value = new Map()
		// cityGroupData.value: {ABCDE=> {a:[],b:[],c:[],d:[],e:[] }}
		cityGroupData.value.set('ABCDE', undefined)
		cityGroupData.value.set('FGHJ', undefined)
		cityGroupData.value.set('KLMN', undefined)
		cityGroupData.value.set('PQRST', undefined)
		cityGroupData.value.set('WXYZ', undefined)
	}
	initCityGroupData()

	// 查询城市信息
	const searchCity = async (spell: string) => {
		// cityData.value:  { a:[],b:[],c:[],d:[],e:[] }
		cityData.value = cityGroupData.value?.get(spell)
		if (!cityData.value) {
			loading.value = true
			await searchCityBySpell(spell.split('').join(',')).then((res) => {
				if (res.data) {
					cityGroupData.value?.set(spell, res.data)
				}
				loading.value = false
			})
			cityData.value = cityGroupData.value?.get(spell)
		}
	}

	// 默认选中
	const selectedGroup = ref('ABCDE')
	// 选择城市分组
	const selectCitySpell = (group: string) => {
		selectedGroup.value = group
		loading.value == true ? '' : searchCity(group)
	}
	//选择城市
	const selectCity = (city: any) => {
		emit('selectCity', city.id, 'otherCity')
		closeDialog()
	}
</script>
<template>
	<div>
		<el-dialog
			v-model="visible"
			:before-close="closeDialog"
			ref="dialog"
			:fullscreen="false"
			class="middleDialog"
			width="50%"
			:destroy-on-close="true"
			:close-on-click-modal="false">
			<template #header>
				<span class="header-title">请选择城市</span>

				<!-- 字母 -->
				<div class="header_box">
					<span
						v-for="(group, index) in cityGroupData"
						:key="index"
						@click="selectCitySpell(group[0])"
						:class="selectedGroup == group[0] ? 'active' : ''"
						>{{ group[0] }}</span
					>
				</div>
			</template>
			<div class="content_box" v-loading="loading">
				<div v-for="(city, key, indexx) in cityData" :key="indexx" class="city-content">
					<span class="city-title">{{ key.toString().toUpperCase() }}</span>
					<div class="city-list">
						<template v-for="(item, indexxx) in city" :key="indexxx">
							<span v-if="item.level == 2" class="city" @click="selectCity(item)">{{ item.name }}</span>
						</template>
					</div>
				</div>
			</div>
		</el-dialog>
	</div>
</template>

<style scoped lang="scss">
	$green: #00a6a7;

	:deep(.el-dialog__body) {
		top: 120px !important;
	}
	.header-title {
		line-height: 24px;
		font-size: 18px;
		color: #303133;
		white-space: nowrap;
		position: absolute;
	}

	.header_box {
		margin-top: 30px;
		background: #f9fafb;
		overflow: hidden;
		width: 100%;
		height: 39px;
		span {
			width: 130px;
			display: inline-block;
			line-height: 39px;
			position: relative;
			cursor: pointer;
			text-align: center;
			user-select: none;
			transition: all 0.2s linear;
			&.active,
			&:hover {
				color: $green;
			}
		}
	}

	.content_box {
		:deep(.el-loading-spinner) {
			margin-top: 10%;
			.path {
				stroke: $green;
			}
		}
		.city-content {
			display: flex;
		}
		.city-title {
			width: 11.2%;
			color: $green;
			text-align: left;
			line-height: 40px;
			cursor: pointer;
		}
		.city-list {
			width: 88.8%;
			text-align: left;
			.city {
				width: 20%;
				text-align: left;
				margin-bottom: 8px;
				float: left;
				line-height: 40px;
				cursor: pointer;
				padding-right: 10px;
				overflow: hidden;
				text-overflow: ellipsis;
				white-space: nowrap;
				&:hover {
					color: $green;
				}
			}
		}
	}
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值