Vue.js实现城市二级联动,核心是通过响应式数据与计算属性动态更新城市列表,首先定义省份数组,每个省份包含对应城市数据,用v-model绑定选中的省份与城市,当省份选择变化时,计算属性根据当前省份过滤出对应城市数组,实现城市列表动态更新,模板中通过两个下拉选择框联动,确保选择省份后自动加载对应城市,提升交互体验,整个过程利用Vue数据驱动特性,无需手动操作DOM,高效实现联动效果。
Vue.js 实现城市二级联动:从数据绑定到交互优化
在城市信息选择、地址填写等场景中,"省份-城市"二级联动是非常常见的需求,用户选择省份后,城市列表自动更新为对应省份下的城市,这种交互能显著提升用户体验,本文将基于 Vue.js,从数据结构设计到组件实现,一步步带你掌握城市二级联动的核心逻辑,并附上完整代码示例和性能优化技巧。
为什么选择 Vue.js 实现二级联动?
Vue.js 的核心优势在于响应式数据绑定和组件化开发,在二级联动场景中,当用户选择省份时,Vue 能自动追踪数据变化,并高效更新城市列表,无需手动操作 DOM,Vue 的计算属性(Computed)和事件处理机制,能让代码更简洁、易维护,相比原生 JavaScript 或 jQuery,Vue 的实现方式更符合现代前端开发的工程化需求,特别适合构建可复用、可维护的表单组件。
实现步骤:从数据准备到组件渲染
数据结构设计
首先需要明确"省份-城市"的数据结构,我们可以用一个数组存储省份信息,每个省份对象包含 name(省份名)和 cities(该省份下的城市数组)。
const regionData = [
{
name: "北京市",
cities: ["东城区", "西城区", "朝阳区", "丰台区", "海淀区", "通州区"]
},
{
name: "上海市",
cities: ["黄浦区", "徐汇区", "长宁区", "静安区", "普陀区", "虹口区"]
},
{
name: "广东省",
cities: ["广州市", "深圳市", "珠海市", "东莞市", "佛山市", "中山市", "江门市"]
},
{
name: "江苏省",
cities: ["南京市", "苏州市", "无锡市", "常州市", "徐州市", "南通市", "连云港市"]
},
{
name: "浙江省",
cities: ["杭州市", "宁波市", "温州市", "嘉兴市", "绍兴市", "金华市"]
}
]
这种结构清晰直观,便于后续通过省份名查找对应城市,在实际项目中,这些数据通常来自后端 API,可以通过 axios 等库异步获取。
搭建 Vue 项目与模板结构
我们可以通过 Vue CLI 快速创建项目,或直接使用 CDN 引入 Vue(适合简单示例),这里以 CDN 方式为例,创建一个 index.html 文件:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Vue.js 城市二级联动</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: #f5f7fa;
line-height: 1.6;
}
.container {
max-width: 600px;
margin: 50px auto;
padding: 30px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
h2 {
color: #303133;
margin-bottom: 20px;
font-size: 24px;
}
.select-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #606266;
font-size: 14px;
}
select {
width: 100%;
padding: 10px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 14px;
color: #606266;
background-color: #fff;
transition: border-color 0.2s;
cursor: pointer;
}
select:hover {
border-color: #c0c4cc;
}
select:focus {
outline: none;
border-color: #409eff;
}
select:disabled {
background-color: #f5f7fa;
cursor: not-allowed;
opacity: 0.7;
}
.result {
margin-top: 20px;
padding: 12px;
background-color: #ecf5ff;
border-radius: 4px;
color: #409eff;
font-size: 14px;
}
.empty-option {
color: #909399;
}
</style>
</head>
<body>
<div id="app" class="container">
<h2>城市选择(二级联动)</h2>
<div class="select-group">
<label for="province">选择省份:</label>
<select id="province" v-model="selectedProvince">
<option value="" class="empty-option">请选择省份</option>
<option v-for="province in regionData"
:key="province.name"
:value="province.name">
{{ province.name }}
</option>
</select>
</div>
<div class="select-group">
<label for="city">选择城市:</label>
<select id="city" v-model="selectedCity" :disabled="!selectedProvince">
<option value="" class="empty-option">请先选择省份</option>
<option v-for="city in currentCities"
:key="city"
:value="city">
{{ city }}
</option>
</select>
</div>
<div class="result" v-if="selectedProvince && selectedCity">
已选择:{{ selectedProvince }} - {{ selectedCity }}
</div>
</div>
<script>
const { createApp, ref, computed, watch } = Vue;
createApp({
setup() {
// 省份数据
const regionData = ref([
{
name: "北京市",
cities: ["东城区", "西城区", "朝阳区", "丰台区", "海淀区", "通州区"]
},
{
name: "上海市",
cities: ["黄浦区", "徐汇区", "长宁区", "静安区", "普陀区", "虹口区"]
},
{
name: "广东省",
cities: ["广州市", "深圳市", "珠海市", "东莞市", "佛山市", "中山市", "江门市"]
},
{
name: "江苏省",
cities: ["南京市", "苏州市", "无锡市", "常州市", "徐州市", "南通市", "连云港市"]
},
{
name: "浙江省",
cities: ["杭州市", "宁波市", "温州市", "嘉兴市", "绍兴市", "金华市"]
}
]);
// 选中的省份和城市
const selectedProvince = ref("");
const selectedCity = ref("");
// 计算当前省份对应的城市列表
const currentCities = computed(() => {
if (!selectedProvince.value) return [];
const province = regionData.value.find(p => p.name === selectedProvince.value);
return province ? province.cities : [];
});
// 监听省份变化,重置城市选择
watch(selectedProvince, (newProvince) => {
selectedCity.value = "";
});
return {
regionData,
selectedProvince,
selectedCity,
currentCities
};
}
}).mount("#app");
</script>
</body>
</html>
核心逻辑解析
(1)响应式数据绑定
selectedProvince 和 selectedCity 通过 ref 定义为响应式数据,分别绑定到两个 <select> 元素的 v-model,当用户选择选项时,Vue 会自动更新对应的数据值,无需手动操作 DOM,这是 Vue 响应式系统的核心优势。
(2)计算属性动态过滤城市列表
`current