vue3原生下拉

<template>
  <div class="demo-collapse">
    <div class="box">
      <div
        class="title-list"
        v-for="(item, index) in collapseLists"
        :key="index"
      >
        <div class="title-wrap" @click="isOpen(index)">
          <span class="title">{{ item.title }}</span>
          <ArrowDownBold class="icon" />
        </div>
        <div :class="item.Flag ? 'content active' : 'content'">
          {{ item.content }}
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { reactive, ref } from "vue";
// 引入icon
import { ArrowDownBold } from "@element-plus/icons-vue";
// 定义是否展开的变量
const openFlag = ref<boolean>(false);
// 数据
const collapseLists = reactive([
  {
    title: "数据安全法",
    content:
      "(对您的数据进行安全评估)专业法律专家针对《中华人民共和国数据安全法》法律条款深度解读,提供基于国家立法背景下对各行业组织机构数据发展战略、安全合规路线的专业咨询建议。",
    Flag: false,
  },
  {
    title: "个人信息保护法",
    content:
      "(保护个人信息权益)专业法律专家针对《中华人民共和国个人信息保护法》法律条款深度解读,基于国家立法背景,为广大民众提高对个人信息合法权益保护的认知、各行业涉及个人信息处理服务的组织机构提升其合规度、专业度提供专业咨询建议。",
    Flag: false,
  },
  {
    title: "App合规检测",
    content:
      "(App、软件产品隐私数据合规性自动化检测服务。)App安全合规检测服务,是全面检测移动应用中存在的不合规项,包含App 收集使用个人信息行为、个人信息存储方式、第三方SDK行为分析、App 运营者对用户权益保障、等其他违规违法进行评测。深度挖掘APP隐私合规风险源头。",
    Flag: false,
  },
  {
    title: "企业风险管理",
    content:
      "(最小的成本收获最大的安全保障)风险管理是社会组织或者个人用以降低风险的消极结果的决策过程,通过风险识别、风险估测、风险评价,并在此基础上选择与优化组合各种风险管理技术,对风险实施有效控制和妥善处理风险所致损失的后果,从而以最小的成本收获最大的安全保障。",
    Flag: false,
  },
  {
    title: "数据资产管理合规检测",
    content:
      "(评估企业数据资产管理合规性)依据《中华人民共和国数据安全法》第二十一条,评估企业数据资产管理规范化水平,数据资产分类分级程度,生成数据资产管理合规报表,让管理人员实时了解公司数据资产管理合规现状。",
    Flag: false,
  },
  {
    title: "GDPR",
    content:
      "(GDPR是当今生效的最强有力的全球隐私法。)由欧盟创建,用于规范组织如何收集、处理和保护欧盟居民的个人数据。它旨在通过让数据主体控制其个人数据的获取、使用和共享的方式来加强隐私权。GDPR确定了严格的隐私保护标准,要求企业对个人数据存储、传输、访问方式以及审计进行更大力度地监督。",
    Flag: false,
  },
]);
const isOpen = (index: number) => {
  if (collapseLists[index].Flag) {
    collapseLists[index].Flag = false;
  } else {
    collapseLists.forEach((item) => {
      item.Flag = false;
    });
    collapseLists[index].Flag = true;
  }
};
</script>
<style lang="less" scoped>
.demo-collapse {
  .box {
    margin: auto;
    position: relative;
    display: flex;
    flex-wrap: wrap;
    width: 600px;
    .title-list {
      width: 300px;
      .title-wrap {
        border-bottom: 1px solid #ccc;

        .title {
          font-size: 20px;
          height: 25px;
          line-height: 25px;
        }
        .icon {
          width: 20px;
          height: 20px;
          vertical-align: middle;
          margin-top: -5px;
        }
      }
      .content {
        width: 600px;
        overflow-y: hidden;
        max-height: 0;
        text-align: left;
        // transition: all 0.3s;
      }
      .content.active {
        border-bottom: 1px solid #ccc;
        overflow-y: hidden;
        max-height: 500px;
        transition: all 1s;
      }
    }
    .title-list:nth-child(2n) {
      .content {
        position: relative;
        left: -300px;
      }
    }
  }
}
</style>

<think>嗯,用户想在Vue3里做一个国家、省、市三级联动的下拉选择组件。首先我得回忆一下Vue3的相关知识,比如组合式API、响应式数据这些。然后用户提到的element-ui组件,他们之前的经验里element的组件把三级放在同一个select里,数据绑定不太方便,所以需要自己封装。那可能需要三个独立的下拉框,分别对应国家、省、市,且后一级的选项依赖于前一级的选择。 首先,数据结构方面,可能需要一个嵌套的数据结构,比如国家数组,每个国家对象包含省份数组,每个省份又包含城市数组。数据可以从后端接口获取,或者前端静态数据。考虑到性能,可能需要用computed属性来动态计算省份和城市的列表,这样当国家或省份变化时,下级选项会自动更新。 然后是组件的状态管理。使用ref来存储选中的国家、省、市的值。当国家改变时,需要清空省和市的选中值;同样,省改变时,清空市的选中值。这可以用watch或者直接在change事件里处理。 接着是UI部分,用户可能希望使用Element Plus的下拉组件,或者原生的select元素。不过Element Plus的级联组件可能不符合需求,因为用户提到需要分开三个下拉框。所以应该用三个el-select组件,每个的选项由前一个的选择决定。 另外,数据绑定方面,使用v-model来绑定选中的值,同时用:disabled属性控制下级下拉框的禁用状态,直到上级有选择。比如,未选择国家时,省份的下拉框是禁用的。 还需要考虑组件的数据来源,可能需要通过props传入国家省市的数据,或者组件内部自己获取。这里用户可能希望组件是通用的,所以通过props传入比较合理。 然后,用户可能需要触发事件,当所有选择完成时,或者每个选择变化时,通知父组件。比如用emit发送选中的国家、省、市的值。 现在,具体实现步骤大概是这样的: 1. 定义响应式变量:selectedCountry, selectedProvince, selectedCity,使用ref初始化。 2. 定义计算属性:provinces,根据selectedCountry的值过滤出对应的省份列表;cities同理,根据selectedProvince过滤。 3. 在模板里放置三个el-select,分别绑定到这三个变量,选项分别是countries、provinces、cities。 4. 在国家的change事件里,重置省和市的值;省的change事件里,重置市的值。 5. 使用watch来监听选中的值变化,可能需要将选中的值emit出去。 然后看用户提供的引用,引用1是Vue2的element-ui组件封装,引用2是Vue3+ts的实现,用到了computed和watch。可以借鉴这些方法,比如用computed来动态生成选项,用watch来触发事件。 还需要注意数据格式,比如国家数据可能是这样的结构: countries: [ { id: 1, name: &#39;中国&#39;, provinces: [...] }, ... ] 每个省份有cities数组。这样在计算属性里,当selectedCountry变化时,provinces就是该国家的provinces数组。同理,selectedProvince变化时,cities就是该省份的cities数组。 然后,在模板里,每个下拉框的选项绑定到对应的计算属性,显示name,值可以是整个对象或者id,根据需求。可能需要用value-key如果是对象的话。 另外,禁用下级下拉框的逻辑,比如省份的下拉框在selectedCountry没有值的时候是disabled的,用:disabled="!selectedCountry"。 最后,测试组件是否正常工作,选择国家后省份是否更新,选择省份后城市是否更新,以及选中值是否正确传递。 可能的问题是如何处理数据加载,如果数据量大可能需要异步加载,但用户的需求里可能先假设数据是静态的或者已经加载完成。 总结一下,步骤是:准备数据,定义响应式变量和计算属性,构建模板,处理change事件和状态重置,处理数据绑定和禁用状态,最后emit事件或暴露选中的值。</think>### 分步骤实现联动下拉选择组件 #### 一、数据结构准备 ```typescript interface CityData { id: number name: string children?: ProvinceData[] } interface ProvinceData { id: number name: string children?: CityData[] } const countries = ref<CityData[]>([ { id: 1, name: "中国", children: [ { id: 11, name: "北京", children: [ { id: 1101, name: "东城区" }, { id: 1102, name: "西城区" } ] } ] } ]) ``` #### 二、响应式状态管理 ```typescript const selectedCountry = ref<CityData>() const selectedProvince = ref<ProvinceData>() const selectedCity = ref<CityData>() // 计算省份列表 const provinces = computed(() => { return selectedCountry.value?.children || [] }) // 计算城市列表 const cities = computed(() => { return selectedProvince.value?.children || [] }) ``` #### 三、选择重置逻辑 ```typescript const handleCountryChange = () => { selectedProvince.value = undefined selectedCity.value = undefined } const handleProvinceChange = () => { selectedCity.value = undefined } ``` #### 四、组件模板实现 ```html <template> <div class="cascade-select"> <el-select v-model="selectedCountry" placeholder="选择国家" @change="handleCountryChange" :options="countries" label-key="name" value-key="id" /> <el-select v-model="selectedProvince" placeholder="选择省份" :disabled="!selectedCountry" @change="handleProvinceChange" :options="provinces" label-key="name" value-key="id" /> <el-select v-model="selectedCity" placeholder="选择城市" :disabled="!selectedProvince" :options="cities" label-key="name" value-key="id" /> </div> </template> ``` #### 五、数据监听与暴露 ```typescript watch([selectedCountry, selectedProvince, selectedCity], ([country, province, city]) => { console.log(&#39;当前选择:&#39;, country?.name, province?.name, city?.name) emit(&#39;change&#39;, { country, province, city }) }) ``` ### 关键实现细节说明 1. **响应式数据流**:使用`computed`实现级联数据过滤,当上级选择变更时自动更新下级选项[^2] 2. **状态重置**:通过@change事件清空下级选择,确保数据一致性 3. **组件解耦**:使用TypeScript接口定义数据结构,增强代码可维护性 4. **UI控制**:通过`:disabled`实现未选择时的禁用状态,提升用户体验
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值