目录
- 前言
- 需求描述
- 实现思路
- 方案一:select 选项 label比对
- 方案二:设置根据用户输入行为设置一个 flag 开关
- 具体实现
- 基于方案一的代码实现
- 基于方案二的代码实现
- 总结
前言
你好,我是喵喵侠。在Web开发中,动态表单的联动操作,是非常常见的需求,尤其是在需要实现复杂逻辑时,更是不可或缺。正好我在工作中,好几次遇到了输入框内容需要被填充的需求,本文将会为你详细介绍这样的需求案例,展示具体实现的思路和实战代码。
需求描述
现在我们来探讨一个具体的需求场景:页面上有一个表单,其中包含一个公司名称输入框(input)和一个所有公司下拉菜单(select),下拉菜单的选项,比方说有腾讯、阿里巴巴、百度和字节跳动。当选中下拉菜单的某个选项时,将该选项的值,会自动填充到输入框中。但如果输入框已经有用户手动输入的值,且该值不在选项列表中,则不覆盖。
更通俗的理解就是,Input 里面有用户手动输入的内容,无论你的选择哪个,都不会覆盖用户原本输入的值,除非他全部删掉,后续的选择才会填充到 Input 里面。如果一开始用户没有输入,则每次的选中都会覆盖上一次的 Input 结果。
其实我接到真实的需求是,有一个地图弹窗,里面有一个百度地图,点击地图任意点位,地图会标点并显示该定位的位置名称,弹窗确定后,这个位置名称会被填充到 Input 输入框中。这里我为了方便理解,把地图弹窗简化成了 Select,核心功能是一样的,掌握了这个方式的实现,类似的都大同小异。
实现思路
我们来拆解下这个需求,把功能点进行拆分如下:
- input 为空,select 选中后自动填充;
- input 有值,且为用户输入,则 select 选中后不填充;
- 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腾讯技术创作特训营最新征文,快来和我瓜分大奖!