vue.js 城市的二级联动

admin 104 0
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)响应式数据绑定

selectedProvinceselectedCity 通过 ref 定义为响应式数据,分别绑定到两个 <select> 元素的 v-model,当用户选择选项时,Vue 会自动更新对应的数据值,无需手动操作 DOM,这是 Vue 响应式系统的核心优势。

(2)计算属性动态过滤城市列表

`current

标签: #js #城市 #二级 #联动