前端表单输入框自动填充和覆盖逻辑的实现

2024-06-20 19:35:43 浏览数 (3)

目录

  • 前言
  • 需求描述
  • 实现思路
    • 方案一:select 选项 label比对
    • 方案二:设置根据用户输入行为设置一个 flag 开关
  • 具体实现
    • 基于方案一的代码实现
    • 基于方案二的代码实现
  • 总结

前言

你好,我是喵喵侠。在Web开发中,动态表单的联动操作,是非常常见的需求,尤其是在需要实现复杂逻辑时,更是不可或缺。正好我在工作中,好几次遇到了输入框内容需要被填充的需求,本文将会为你详细介绍这样的需求案例,展示具体实现的思路和实战代码。

需求描述

现在我们来探讨一个具体的需求场景:页面上有一个表单,其中包含一个公司名称输入框(input)和一个所有公司下拉菜单(select),下拉菜单的选项,比方说有腾讯、阿里巴巴、百度和字节跳动。当选中下拉菜单的某个选项时,将该选项的值,会自动填充到输入框中。但如果输入框已经有用户手动输入的值,且该值不在选项列表中,则不覆盖。

更通俗的理解就是,Input 里面有用户手动输入的内容,无论你的选择哪个,都不会覆盖用户原本输入的值,除非他全部删掉,后续的选择才会填充到 Input 里面。如果一开始用户没有输入,则每次的选中都会覆盖上一次的 Input 结果。

其实我接到真实的需求是,有一个地图弹窗,里面有一个百度地图,点击地图任意点位,地图会标点并显示该定位的位置名称,弹窗确定后,这个位置名称会被填充到 Input 输入框中。这里我为了方便理解,把地图弹窗简化成了 Select,核心功能是一样的,掌握了这个方式的实现,类似的都大同小异。

实现思路

我们来拆解下这个需求,把功能点进行拆分如下:

  1. input 为空,select 选中后自动填充;
  2. input 有值,且为用户输入,则 select 选中后不填充;
  3. input 有值,且为上次 select 填充结果,则 select 选中后覆盖填充。

自动填充很好实现,select 的 change 事件进行赋值就好了,难点在于如何判断当前的 input 的值,是用户输入的,还是 select 填充的呢?

对此我有两种解决方案:

方案一:select 选项 label比对

这个方案很好理解,就是每次 select 选中的时候,当 change 事件触发时,判断当前 input 的值,是否能与 select 的 option 选项中的某一项的 label 匹配的上,如果这个 input 值和这一项的 label 完全相等,那么可以视为这个 input 值是来自于上次的 select 选择,否则change 事件不执行覆盖填充操作。

这里有个细节,那就是存在输入的值和 select 值完全相等的情况,不过这个不影响,因为从效果上来看,都是一样的。

方案二:设置根据用户输入行为设置一个 flag 开关

这种方案和方案一的关注点不同,它不关心 option 里面有什么样的 label,而是关注这个 input 内容是不是来自用户的。要想判断其实很简单,只需要监听一下 input 事件就好了。如果 input 事件执行了,且 input 的值不为空,那么可以视为这个 input 的值是来自于用户手动输入,不能select 选中后无法覆盖,否则 select 选中后可以覆盖。

顺便说一下,粘贴文本到 input 输入框,也是可以触发 input 事件的。

具体实现

基于方案一的代码实现

代码语言:vue复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Element-UI 表单示例</title>
  <!-- 引入Element-UI的CSS和JavaScript -->
  <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/theme-chalk/index.min.css">
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/index.min.js"></script>
</head>
<body>
  <div id="app">
    <el-form>
      <el-form-item label="公司名称">
        <el-input v-model="form.companyName" style="width: 200px" placeholder="请输入"></el-input>
      </el-form-item>
      <el-form-item label="选择公司">
        <el-select v-model="form.selectedCompany" @change="handleCompanyChange">
          <el-option
            v-for="item in companies"
            :key="item.value"
            :label="item.label"
            :value="item.label">
          </el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </div>

  <script>
    new Vue({
      el: '#app',
      data() {
        return {
          form: {
            companyName: '',
            selectedCompany: '',
          },
          companies: [
            { value: '腾讯', label: '腾讯' },
            { value: '阿里巴巴', label: '阿里巴巴' },
            { value: '百度', label: '百度' },
            { value: '字节跳动', label: '字节跳动' },
          ],
        };
      },
      methods: {
        handleCompanyChange(value) {
          const isfindCompanyName = this.companies.some(company => company.label == this.form.companyName);
          console.log(isfindCompanyName)
          if (!isfindCompanyName && this.form.companyName) {
            return false
          }
          this.form.companyName = value;
        },
      },
    });
  </script>
</body>
</html>

实现效果如下:

基于方案二的代码实现

代码语言:vue复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Element-UI 表单示例</title>
  <!-- 引入Element-UI的CSS和JavaScript -->
  <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/theme-chalk/index.min.css">
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/index.min.js"></script>
</head>
<body>
  <div id="app">
    <el-form>
      <el-form-item label="公司名称">
        <el-input v-model="form.companyName" style="width: 200px" placeholder="请输入" @input="handleInput"></el-input>
      </el-form-item>
      <el-form-item label="选择公司">
        <el-select v-model="form.selectedCompany" @change="handleCompanyChange">
          <el-option
            v-for="item in companies"
            :key="item.value"
            :label="item.label"
            :value="item.label">
          </el-option>
        </el-select>
      </el-form-item>
    </el-form>
  </div>

  <script>
    new Vue({
      el: '#app',
      data() {
        return {
          form: {
            companyName: '',
            selectedCompany: '',
          },
          companies: [
            { value: '腾讯', label: '腾讯' },
            { value: '阿里巴巴', label: '阿里巴巴' },
            { value: '百度', label: '百度' },
            { value: '字节跳动', label: '字节跳动' },
          ],
          inputFlag: false
        };
      },
      methods: {
        handleInput(value) {
          this.inputFlag = !!value // Vue Cli项目注意是 event.target.value
        },
        handleCompanyChange(value) {
          if (this.inputFlag) {
            return false
          }
          const findCompanyLabel = this.companies.find(item=>item.value == value)?.label
          this.form.companyName = findCompanyLabel
          this.inputFlag = false;
        },
      },
    });
  </script>
</body>
</html>

实现效果也是一样的,这里就不重复放效果图了。

只是注意一点,handleInput方法接受的第一个参数,在 Vue Cli 里面 event 是这个input 的 dom 对象,需要通过 event.target.value获取输入的值,而 上面html 版本的 vue demo 中,第一个参数实际上变成了 value。

总结

虽然这是一个很小的业务功能点,但里面的细节还是有一些的。通过实现公司名称和选择公司选项的联动功能,我们可以大大提升用户填写表单的便捷性和体验。当用户选择公司的时候,自动填充公司名称不仅减少了手动输入的麻烦,还能避免输入错误。这种精细的用户体验设计,虽然看似简单,却能显著提升用户对表单的使用满意度,增强系统的易用性和专业性。做好这些细节的优化,对于整个应用的用户体验都有积极的作用。

如果你有更好的实现思路或看法,欢迎在评论区与我交流。


我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

1 人点赞