JavaScript 实现二级联动是一个常见的前端开发任务,下面给出一种基础的实现方式。
HTML 代码部分:
html
<!-- 省份选择器 -->
<select id="province">
<option value="">请选择省份</option>
<option value="浙江省">浙江省</option>
<option value="广东省">广东省</option>
</select>
<!-- 城市选择器 -->
<select id="city" disabled>
<option value="">请先选择省份</option>
</select>
上述代码中包含了两个 元素,一个表示省份选择器,一个是城市选择器,首先将城市选择器禁用,直到用户选择具体省份时才启用。
JavaScript 代码部分:
javascript
const provinceSelect = document.getElementById('province');
const citySelect = document.getElementById('city');
const cities = [
{ province: '浙江省', name: '杭州市' },
{ province: '浙江省', name: '宁波市' },
{ province: '浙江省', name: '温州市' },
{ province: '广东省', name: '广州市' },
{ province: '广东省', name: '深圳市' },
{ province: '广东省', name: '珠海市' }
];
// 根据所选省份生成城市选项
function generateCityOptions() {
// 获取当前所选省份的值
const province = provinceSelect.value;
// 清空原有城市选项
clearCityOptions();
// 生成新的城市选项
for (let i = 0; i < cities.length; i++) {
const city = cities[i];
if (city.province === province) {
const option = document.createElement('option');
option.value = city.name;
option.text = city.name;
citySelect.appendChild(option);
}
}
// 启用城市选择器
citySelect.disabled = false;
}
// 清空城市选项
function clearCityOptions() {
while (citySelect.firstChild) {
citySelect.removeChild(citySelect.firstChild);
}
// 禁用城市选择器
citySelect.disabled = true;
}
provinceSelect.addEventListener('change', function(event) {
generateCityOptions();
});
generateCityOptions();
上述代码使用了一个名为 cities 的数组存储了所有可选的城市数据。在 generateCityOptions() 函数中根据当前所选省份的值,筛选出对应的城市,然后将它们逐一添加到城市选择器中,并启用该选择器。在 clearCityOptions() 函数中则是清空已有的城市选项,以及禁用该选择器。
最后,通过将 generateCityOptions() 方法绑定到省份选择器的 change 事件上,这样当用户选择省份时就会自动调用该方法,生成相应的城市选项。
以上代码实现了简单的二级联动,可以根据需求进行二次优化和扩展。
vue的写法
下面是基于 Vue 的二级联动的实现方式,采用了 Vue 组件和数据绑定的方式。
HTML 代码部分:
html
<div id="app">
<!-- 省份选择器 -->
<select v-model="selectedProvince">
<option value="">请选择省份</option>
<option v-for="province in provinces" :key="province" :value="province">{{ province }}</option>
</select>
<!-- 城市选择器 -->
<select v-model="selectedCity" :disabled="!selectedProvince">
<option value="">请先选择省份</option>
<option v-for="city in cities" :key="city" :value="city">{{ city }}</option>
</select>
</div>
上述代码中使用了 v-model 指令将选择器的值与 Vue 实例中的数据进行双向绑定,同时也使用了 v-for 指令遍历数组中的每个元素生成具体的选项。在城市选择器中使用了 :disabled 属性,当未选择省份时禁用该选择器。
JavaScript 代码部分:
javascript
new Vue({
el: '#app',
data: {
provinces: ['浙江省', '广东省'],
selectedProvince: '',
cities: []
},
watch: {
// 监听选中省份变化
selectedProvince: function(newValue, oldValue) {
if (newValue) {
this.getCities(newValue);
} else {
this.cities = [];
}
this.selectedCity = '';
}
},
methods: {
// 根据所选省份获取城市数据
getCities: function(province) {
// 模拟异步请求
setTimeout(() => {
if (province === '浙江省') {
this.cities = ['杭州市', '宁波市', '温州市'];
} else if (province === '广东省') {
this.cities = ['广州市', '深圳市', '珠海市'];
}
}, 500);
}
}
});
上述代码中使用了 Vue 实例的 data 属性用来存储组件中所需的数据,其中 provinces 存储所有可选省份、selectedProvince 表示当前所选择的省份、cities 则表示当前省份下可选的所有城市。此外,还定义了一个 watch 属性监控所选省份的变化,并在其发生改变时调用 getCities() 方法获取相应城市数据,最后将得到的数据更新到 cities 变量中。
需要注意的是,这里通过 setTimeout() 方法模拟异步请求,在实际开发中可以使用 Ajax 等技术来从服务端获取数据,具体实现方式视实际情况而定。
以上就是利用 Vue 实现二级联动的代码实现方式,Vue 的组件化封装和数据绑定机制能够提高开发效率,使得代码更加简洁易读。
react+ts写法
以下是基于 React 和 TypeScript 的二级联动的实现方式。
首先,需要为 Option 接口定义一个数据类型:
typescript
interface Option {
value: string;
label: string;
}
然后定义一个叫做 CitySelect 的函数式组件来渲染城市选择器:
typescript
import React, { useState } from 'react';
interface Props {
provinces: Option[];
cities: Record<string, string[]>;
}
function CitySelect({ provinces, cities }: Props) {
const [selectedProvince, setSelectedProvince] = useState('');
const provinceOptions = [{ value: '', label: '请选择省份' }, ...provinces];
const cityOptions = [{ value: '', label: '请先选择省份', disabled: true }];
if (selectedProvince && cities[selectedProvince]) {
for (let i = 0; i < cities[selectedProvince].length; i++) {
const city = cities[selectedProvince][i];
cityOptions.push({ value: city, label: city });
}
}
function handleProvinceChange(event: React.ChangeEvent<HTMLSelectElement>) {
setSelectedProvince(event.target.value);
}
return (
<>
<select value={selectedProvince} onChange={handleProvinceChange}>
{provinceOptions.map(option => (
<option key={option.value} value={option.value}>{option.label}</option>
))}
</select>
<select value={''} disabled={!selectedProvince}>
{cityOptions.map(option => (
<option
key={option.value}
value={option.value}
disabled={option.disabled}
>{option.label}</option>
))}
</select>
</>
);
}
export default CitySelect;
上述代码中使用了 React 的 Hooks 写法,利用 useState 来存储当前所选省份的值,并将其与省份选择器的 value 属性进行绑定,以便在用户选择项时获取到最新的省份数据。同时也定义了两个数组,provinceOptions 存储所有可选的省份,cityOptions 用来动态渲染城市选择器,并控制其启用或禁用状态。
在组件中还定义了一个 handleProvinceChange() 方法来处理省份选择器的变化,并更新当前所选省份的值。该方法被绑定到省份选择器的 onChange 事件上,一旦用户操作省份选择器,则会自动调用该方法。
最后,使用 map() 方法遍历数据,生成相应的 元素。当用户选择省份时,会根据对应城市数据动态渲染城市选择器的选项,并启用该选择器;当用户没有选择省份时,则不能通过城市选择器选择任何选项。
至此,React + TypeScript 实现二级联动就完成了。
vue3+ts写法
以下是基于 Vue 3 和 TypeScript 的二级联动的实现方式。
首先,需要为 Option 接口定义一个数据类型:
typescript
interface Option {
value: string;
label: string;
}
然后,在 src 目录下新建一个名为 CitySelect.vue 的组件文件,并在其中编写如下代码:
<template>
<div>
<select v-model="selectedProvince" @change="handleProvinceChange">
<option value="" disabled selected>请选择省份</option>
<option v-for="province in provinceOptions" :value="province.value" :key="province.value">{{ province.label }}</option>
</select>
<select :disabled="!selectedProvince">
<option value="" disabled>{{ selectedProvince ? '请选择城市' : '请先选择省份' }}</option>
<option v-for="city in cityOptions" :value="city.value" :key="city.value">{{ city.label }}</option>
</select>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
interface Props {
provinces: Option[];
cities: Record<string, string[]>;
}
export default defineComponent({
name: 'CitySelect',
props: {
provinces: {
type: Array as () => Option[],
required: true
},
cities: {
type: Object as () => Record<string, string[]>,
required: true
}
},
setup(props: Props) {
const selectedProvince = ref('');
const provinceOptions = [{ value: '', label: '请选择省份' }, ...props.provinces];
const cityOptions = [{ value: '', label: selectedProvince.value ? '请先选择省份' : '请选择城市', disabled: true }];
function handleProvinceChange(event: Event) {
const target = event.target as HTMLSelectElement;
selectedProvince.value = target.value;
cityOptions.splice(2, cityOptions.length - 2);
if (selectedProvince.value && props.cities[selectedProvince.value]) {
for (let i = 0; i < props.cities[selectedProvince.value].length; i++) {
const city = props.cities[selectedProvince.value][i];
cityOptions.push({ value: city, label: city });
}
}
}
return {
selectedProvince,
provinceOptions,
cityOptions,
handleProvinceChange
};
}
});
</script>
上述代码中定义了一个名为 CitySelect 的 Vue 组件来渲染城市选择器。在组件中使用了 ref 创建了一个响应式的 selectedProvince 变量,用于存储当前所选省份的值,并将其与省份选择器的 v-model 指令进行绑定。
同时也定义了两个数组,provinceOptions 存储所有可选的省份,cityOptions 用来动态渲染城市选择器,并控制其启用或禁用状态。为了保证正确性,需要在选项列表的第一个位置分别加入“请选择省份”和“请选择城市”这两个选项。
在组件中还定义了一个 handleProvinceChange() 方法来处理省份选择器的变化,并通过调用 props.cities 对象来获取到对应的城市数据源,并更新 cityOptions 数组内容。该方法被绑定到省份选择器的 change 事件上,一旦用户操作省份选择器,则会自动调用该方法。
最后,在使用这个组件的地方,只需要将 provinces 和 cities 这两项数据传递给组件即可,例如:
<template>
<CitySelect :provinces="provinces" :cities="cities" />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import CitySelect from '@/components/CitySelect.vue';
interface Province {
name: string;
code: string;
}
export default defineComponent({
name: 'App',
components: {
CitySelect
},
data() {
return {
provinces: [{ value: '', label: '请选择省份' }, { value: 'gd', label: '广东省' }],
cities: {
gd: ['广州市', '深圳市']
}
};
}
});
</script>
由于在 CitySelect.vue 组件中已经定义了 props 接口规范,因此在使用组件时需要传入与之匹配的 provinces 和 cities 数据。在本例中,例子数据中包含一个名为 provinces 的数组和一个名为 cities 的对象。其中 provinces 是一个包含所有可选省份的选项列表,而 cities 则是一个字典对象,键名为省份的代码,对应的值为一个包含该省份下所有可选城市名称的字符串数组。
至此,Vue 3 + TypeScript 实现二级联动就完成了。如果想要上线发布项目,可以执行 npm run build 命令来生成最终的生产版代码。