如何实现两个下拉选择框 select选中联动效果?

简介: 本文通过一个公司与产品联动的下拉选择案例,详细讲解了Element UI中双向联动下拉框的实现方法。涵盖数据过滤、回显处理、重置功能及注意事项,结合Vue实战代码,帮助开发者提升表单交互体验,适用于各类关联选择场景的开发参考。(238字)

目录

前言

最近接到一个需求,大概是这样的:

某一个页面,上面是查询项,下面是列表。查询项中有两个下拉选择框,都是查询条件。这两个选择框是父子级的关系。当我选中第一个选择框某一项时,第二个选择框的下拉项会发生变化;当选择第二个选择框的某一项时,需要回填第一个选择框的值。

大概是这么个效果,这么描述起来有点复杂。下面我们来看一个实际案例,这样就会清晰很多。

案例

假设现在有两个下拉选择框,选择框1代表公司,选择框 2 代表产品。如下图所示:

请在此添加图片描述

实现的功能要求如下:

  1. 默认情况下,选择框 1 点击可以查看所有的公司选项,选择框 2 可以看到所有的产品选项(不区分公司)。
  2. 选择选择框 1 中,任意一个公司后(如:腾讯),选择框 2 中只会出现与该公司(如:腾讯)相关的产品选项。
  3. 如果一开始选中的选择框 2的某个产品(如:微信),那么选择框 1 会被默认选中该产品对应的公司(如:腾讯)
  4. 再外加一个重置的按钮,点击重置后,两个选择框都恢复到初始状态,也就是单独点击可以查看全部选项。

通过这个案例描述,加上配图,是不是就清晰许多了。下面我们来一起实现这样的功能吧。

功能实现

首先我们写一个页面布局,可以手写,也可以借助腾讯云 AI 代码助手来生成。

这里我以 element ui 为例子,用 AI 助手来生成了,prompt 如下:

请帮我生成一个 element-ui 表单页面,这个页面有两个选择框,分别是:
选择框el-select 公司(腾讯、百度、阿里)
选择框el-select 产品(QQ、微信、钉钉、淘宝、百度网盘、百度输入法)
其中QQ、微信是腾讯的产品,钉钉、淘宝是阿里的产品,百度网盘、百度输入法是百度的产品。
他们有从属关系,我需要你帮我实现以下功能:
1. 默认情况下,选择框 1 点击可以查看所有的公司选项,选择框 2 可以看到所有的产品选项(不区分公司)。
2. 选择选择框 1 中,任意一个公司后(如:腾讯),选择框 2 中只会出现与该公司(如:腾讯)相关的产品选项。
3. 如果一开始选中的选择框 2的某个产品(如:微信),那么选择框 1 会被默认选中该产品对应的公司(如:腾讯)
4. 再外加一个重置的按钮,点击重置后,两个选择框都恢复到初始状态,也就是单独点击可以查看全部选项。
-----满足上面这些要求后,给我生成一个 bootcdn 版本的element-ui 的html 版本的 demo

于是我们得到了下面的文件内容:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Element UI 表单页面</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
    <div id="app">
        <el-form ref="form" label-position="left" label-width="120px">
            <el-form-item label="公司">
                <el-select v-model="company" placeholder="请选择公司">
                    <el-option
                        v-for="item in companies"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                    ></el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="产品">
                <el-select v-model="product" placeholder="请选择产品">
                    <el-option
                        v-for="item in products"
                        :key="item.value"
                        :label="item.label"
                        :value="item.value"
                    ></el-option>
                </el-select>
            </el-form-item>
            <el-form-item>
                <el-button @click="resetForm">重置</el-button>
            </el-form-item>
        </el-form>
    </div>

   <script src="https://unpkg.com/vue@2.6.12/dist/vue.js"></script>
   <script src="https://unpkg.com/element-ui@2.15.7/lib/index.js"></script>
   <script>
        new Vue({
    
            el: '#app',
            data() {
    
                return {
    
                    company: '',
                    product: '',
                    companies: [
                        {
     label: '腾讯', value: 'tencent' },
                        {
     label: '百度', value: 'baidu' },
                        {
     label: '阿里', value: 'alibaba' }
                    ],
                    products: [
                        {
     label: 'QQ', value: 'qq', company: 'tencent' },
                        {
     label: '微信', value: 'wechat', company: 'tencent' },
                        {
     label: '钉钉', value: 'dingtalk', company: 'alibaba' },
                        {
     label: '淘宝', value: 'taobao', company: 'alibaba' },
                        {
     label: '百度网盘', value: 'baidunetdisk', company: 'baidu' },
                        {
     label: '百度输入法', value: 'baiduinput', company: 'baidu' }
                    ]
                };
            },
            watch: {
    
                company(newValue) {
    
                    this.product = '';
                    if (newValue === 'tencent') {
    
                        this.products = [
                            {
     label: 'QQ', value: 'qq', company: 'tencent' },
                            {
     label: '微信', value: 'wechat', company: 'tencent' }
                        ];
                    } else if (newValue === 'alibaba') {
    
                        this.products = [
                            {
     label: '钉钉', value: 'dingtalk', company: 'alibaba' },
                            {
     label: '淘宝', value: 'taobao', company: 'alibaba' }
                        ];
                    } else if (newValue === 'baidu') {
    
                        this.products = [
                            {
     label: '百度网盘', value: 'baidunetdisk', company: 'baidu' },
                            {
     label: '百度输入法', value: 'baiduinput', company: 'baidu' }
                        ];
                    }
                },
                product(newValue) {
    
                    this.company = newValue.company;
                }
            },
            methods: {
    
                resetForm() {
    
                    this.company = '';
                    this.product = '';
                }
            }
        });
    </script>
</body>
</html>

AI 助手虽然给我做出了页面,但是没有替换 cdn,联动还是有问题。不过不要紧,我们来手动实现下功能需求。

请在此添加图片描述

从上面代码可以注意到,products 作为第二个选择框的选项,额外引入了company的字段,这个字段非常关键,当你选中某一项的产品的时候,你能立马知道对应的公司是哪家。真实业务开发过程中,这一点需要跟后端开发沟通,要求对方通过接口返回的数据,包括company这一项。

请在此添加图片描述

仔细想想,其实公司的选项是不需要做过滤的,只有产品需要做过滤。那么思路就很清晰了,如何给产品做过滤,以及如何回显公司。

给产品做过滤,我有两个思路:

  1. 备份一下原有的全量数据,写到 data 里面命名为productsDefault,当选中公司后,将productsDefault用 filter 方法,判断筛选出等于当前公司的项,返回数组并赋值给products。
  2. 还是用原来的 products 这个数组,只是给每一项额外新增一个字段,比方说叫 display,设置为 true 就是显示,设置为 false 就是隐藏,绑定到 el-option上,控制是否渲染。

其实两个方法思路都是过滤,只是思路2 不需要额外准备一个备份的变量。但思路 2 需要注意一点,v-if 和 v-for 不能混用,这里需要再外层用 template 上加 v-for,然后再在里面加 v-if。

至于公司的选中的回显,只需要在产品选择框上加一个 change 事件,每次改变后,根据当前产品的 value ,用 find 方法查询对应的公司,然后把公司选择框的 v-model 赋值一下就好了。

重置就更好做了,直接用 forEach 把products所有的每一项的 display 设置为 true ,把两个选择框的 v-mol 置为空字符串即可。

另外需要注意一点,每次选择公司后,需要把上次选中的产品给清空掉,我是写完才发现有这个问题的。

下面附上完整的代码吧:

<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Element UI 表单页面</title>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>

<body>
  <div id="app">
    <el-form ref="form" label-position="left" label-width="120px">
      <el-form-item label="公司">
        <el-select v-model="company" placeholder="请选择公司" @change="handleChange1">
          <el-option v-for="item in companies" :key="item.value" :label="item.label" :value="item.value"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="产品">
        <el-select v-model="product" placeholder="请选择产品" @change="handleChange2">
          <template v-for="item in products">
          <el-option
            v-if="item.display" :key="item.value" :label="item.label" :value="item.value"></el-option>
          </template>
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button @click="resetForm">重置</el-button>
      </el-form-item>
    </el-form>
  </div>
  <script src="https://unpkg.com/vue@2.6.12/dist/vue.js"></script>
  <script src="https://unpkg.com/element-ui@2.15.7/lib/index.js"></script>
  <script>
    new Vue({
    
      el: '#app',
      data() {
    
        return {
    
          company: '',
          product: '',
          companies: [
            {
     label: '腾讯', value: 'tencent' },
            {
     label: '百度', value: 'baidu' },
            {
     label: '阿里', value: 'alibaba' }
          ],
          products: [
            {
     label: 'QQ', value: 'qq', company: 'tencent' },
            {
     label: '微信', value: 'wechat', company: 'tencent' },
            {
     label: '钉钉', value: 'dingtalk', company: 'alibaba' },
            {
     label: '淘宝', value: 'taobao', company: 'alibaba' },
            {
     label: '百度网盘', value: 'baidunetdisk', company: 'baidu' },
            {
     label: '百度输入法', value: 'baiduinput', company: 'baidu' }
          ]
        };
      },
      created() {
    
        this.products.forEach(item => item.display = true)
      },
      methods: {
    
        // 选择公司
        handleChange1(value) {
    
          // 根据公司过滤产品,用 forEach 过滤
          this.products.forEach(item => item.display = item.company == value)
          // 重置产品
          this.product = '';
        },
        // 选择产品
        handleChange2(value) {
    
          // 找到选中的那一项
          const findProduct = this.products.find(item => item.value === value);
          // 把这一项的对应的公司,赋值给 company(注意:这里要加个判断,不然undefined 再取值会报错)
          if(findProduct){
    
            this.company = findProduct.company;
          }
        },
        resetForm() {
    
          this.company = '';
          this.product = '';
          this.products.forEach(item => item.display = true)
        }
      }
    });
  </script>
</body>

</html>

实现效果如下:

请在此添加图片描述

这样一来,该有的功能就都实现了,用户体验也会比好很多。如果只需要选择产品的话,可以试试级联选择器,改天我写一篇关于级联选择器的文章。

总结

即使面对一个小案例,实现起来也可能存在一些细节需要注意。稍不留神,就有可能出现各种问题。本文根据我个人在实际业务场景中的需求,设计了一个小案例作为模拟。希望通过这个案例的分享能够为你提供一些帮助和启发。愿这个案例也能够激发更多类似的实际应用场景的思考和探讨。

目录
相关文章
|
6天前
|
JavaScript Linux iOS开发
使用 nvs 工具来切换 node 版本
nvs是一款跨平台Node版本管理工具,支持Windows、macOS和Linux,可轻松切换不同项目的Node版本。本文介绍其安装方法、常用命令(如添加、切换、默认版本设置)及实用技巧,助力多项目高效开发。
76 0
使用 nvs 工具来切换 node 版本
|
6天前
|
前端开发 JavaScript 定位技术
前端表单输入框自动填充和覆盖逻辑的实现
本文介绍Web开发中表单联动的实现方案,针对输入框与下拉框的数据填充需求,提出两种解决思路:一是通过比对选项label判断是否覆盖,二是监听用户输入行为设置flag开关。结合Vue与Element-UI实战代码,详解如何智能控制数据填充逻辑,避免覆盖用户手动输入内容,提升表单交互体验。
55 0
前端表单输入框自动填充和覆盖逻辑的实现
|
6天前
|
Linux 虚拟化 iOS开发
UTM 4.7.5 发布 - 在 macOS 上优雅的使用 QEMU 虚拟化 Windows、Linux 和 macOS
UTM 4.7.5 发布 - 在 macOS 上优雅的使用 QEMU 虚拟化 Windows、Linux 和 macOS
103 0
UTM 4.7.5 发布 - 在 macOS 上优雅的使用 QEMU 虚拟化 Windows、Linux 和 macOS
|
3天前
|
人工智能 小程序 JavaScript
uni-app微信小程序相机组件二次拍照白屏问题的排查与解决
本文分享了在uni-app开发微信小程序时,因状态管理不当导致拍照后图片不显示的bug排查过程。问题根源在于删除照片时将变量设为“#”(truthy值),导致条件渲染逻辑错误。通过彻底清空相关状态并遵循最佳实践,最终解决问题。
42 2
|
6天前
|
文字识别 开发者 Windows
Windows 上值得推荐的软件(第一弹)
本文推荐两款提升Windows使用效率的神器:Listary,实现文件快速搜索与路径跳转;uTools,集快捷启动、剪贴板智能识别与丰富插件于一体,助力高效办公。
57 0
Windows 上值得推荐的软件(第一弹)
|
6天前
|
JavaScript 数据可视化 视频直播
如何手动停止 videojs 直播视频流 m3u8 请求?
在可视化大屏项目中,多个VideoJS组件播放m3u8流时,即使暂停仍持续请求,导致页面卡顿。通过监听display属性,结合`dispose()`销毁实例并重建同ID的video DOM元素,有效释放资源且保留组件结构,解决性能问题,提升用户体验。
87 0
|
5天前
|
人工智能 前端开发 搜索推荐
你不知道的 CSS flex 陷阱
本文通过一个实际案例,深入解析了使用CSS Flexbox布局时,因`flex-wrap: wrap`与父容器高度设置导致的意外间距问题。作者指出,该现象源于`align-content`属性的默认行为(stretch),并通过设置`align-content: flex-start`有效解决。文章还对比了MDN与W3C文档对该属性默认值的差异,并系统梳理了`flex-wrap`和`align-content`的用法,帮助开发者更好掌握多行Flex布局的控制技巧。
38 0
你不知道的 CSS flex 陷阱
|
3天前
|
前端开发 程序员 API
作为前端开发,分享下我在编程中的好习惯
前端开发喵喵侠分享多年实战总结的8个编程好习惯:写前先思考、注释重“为什么”、规范命名、代码自检、写文档、Git提交规范化、表单提示友好化、果断删除无用代码。习惯决定代码质量,写出半年后自己仍能读懂的代码,才是成熟的开始。
21 0
|
5天前
|
JavaScript 前端开发 数据可视化
如何优雅地处理Echarts环形图中的小数显示?
本文介绍了在数据可视化中处理数字格式的三种方法,重点解决保留两位小数并去除末尾多余0的问题。通过字符串操作、正则表达式和Number类型转换,实现简洁高效的数字格式化,推荐使用Number方法最优。
34 0
|
5天前
|
JavaScript 前端开发 Shell
技术实践:快速批量下载网站图片资源实现方法
本文介绍了三种批量下载图片的方法:使用HTML页面、Node.js脚本和Bash结合Wget命令。重点推荐第三种,仅需几行命令即可高效完成下载,无需编程环境,兼容性强,适合快速批量获取网络图片资源。
98 0

热门文章

最新文章