修复el-autocomplete组件监听change返回值始终是输入框的值而非选中的“输入建议”值

修复el-autocomplete组件监听change返回值始终是输入框的值而非选中的“输入建议”值

需求

用户是在输入框输入值后模糊搜索某旅客表姓名
输入框需要在失焦后校验输入值的姓名格式

问题

模拟用户点击模糊匹配的旅客姓名列表后
提示格式错误

环境

项目Value
电脑M1 MBA2020
系统BigSur 11.6
node15.9
element-ui2.15.6

重现代码

<template>
  <div id="app">
    <el-autocomplete v-model="test" :fetch-suggestions="querySearch" @select="handleSelect" @change="handleChange" ></el-autocomplete>
  </div>
</template>
export default {
  data () {
    return {
      test: '',
      restaurants: [{ "value": "三全鲜食(北新泾店)", "address": "长宁区新渔路144号" }]
    }
  },
  methods: {
    handleChange (val) {
      alert(val)
    },
    handleSelect(item) {
      console.log(item);
    },
    querySearch(queryString, cb) {
      var restaurants = this.restaurants;
      var results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants;
      // 调用 callback 返回建议列表的数据
      cb(results);
    },
    createFilter(queryString) {
      return (restaurant) => {
        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
      };
    }
  }
}

code基本照搬 官网 el-autocomplete组件demo

原因

找到el-autocomplete组件源码:node_modules/elementui-vue/node_modules/element-ui/packages/autocomplete/src/autocomplete.vue
查找触发chang事件代码

handleChange(value) {
  this.$emit('change', value);
},

查找调用handleChange函数的代码

... other code
<el-input
  ref="input"
  v-bind="[$props, $attrs]"
  @input="handleInput"
  @change="handleChange"
  @focus="handleFocus"
  @blur="handleBlur"
  @clear="handleClear"
  @keydown.up.native.prevent="highlight(highlightedIndex - 1)"
  @keydown.down.native.prevent="highlight(highlightedIndex + 1)"
  @keydown.enter.native="handleKeyEnter"
  @keydown.native.tab="close"
>
... other code

可以发现el-autocomplete组件直接监听子组件input的change事件并原封不动把值抛出来

解决方案

当绑定了指令的组件被插入到dom时,修改组件的handleChange事件
注意:该方法仅适用于element-ui 2.13.2+版本,请看最终方案

  • 获取autocomplete组件实例,并修改handleChange函数
  • 判断是否已经展开输入建议,否则直接触发change,是则接下面
  • 给autocomplete组件创建观察函数和自定义事件
    • 1: 用户选择了输入建议-监听到select事件,移除观察函数,触发change事件并返回正确的值
    • 2: 用户不选择输入建议并输入框失焦使输入建议组件关闭-观察到autocomplete组件里的suggestions子组件的showPopper变化,移除观察函数,触发change事件
<el-autocomplete v-get-selected-value ...>
</el-autocomplete>
  directives: {
    'get-selected-value': {
      inserted: function () {
        const vnode = arguments[2].child
        vnode.handleChange = val => {
          if (vnode.$refs?.suggestions?.showPopper) {
            const unwatch = vnode.$watch(() => vnode.$refs.suggestions.showPopper, function () {
              unwatch()
              vnode.$emit('change', val)
            })
            vnode.$once('select', item => {
              unwatch()
              vnode.$emit('change', item[vnode.valueKey])
            })
          } else {
            vnode.$emit('change', val)
          }
        }
      }
    }
  }

发现问题

当我把自定义指令代码搬公司项目代码上发现,输入框每input一次就会执行修改的handleChange函数!T-T心累~~
当我再次确认demo的代码没问题后,发现两个项目的element-ui版本不一样。然后分别打开两个项目的autocomplete.vue源码进行对比,发现版本是2.13.0的代码中,handleChange函数直接绑定给input监听,这就解释通了。

<el-input
  ref="input"
  v-bind="[$props, $attrs]"
  @input="handleChange"
  ...
  >

补充文章:element-ui v2.13.2

Bug fixes
Autocomplete
Fix change event bug (#19200 by @sxzz)

终极方案

不动你的handleChange函数,我直接给input子组件加个change事件监听,上代码!

directives: {
    'get-selected-value': {
      inserted: function () {
        const vnode = arguments[2].child
        // 弃用:vnode.handleChange = val => {
        // 这里$off是为了移除高版本代码中新增的@change监听,否则直接加代码会有两个监听事件,触发两次change
        vnode?.$refs?.input && vnode.$refs.input.$off('change').$on('change', val => {
          if (vnode.$refs?.suggestions?.showPopper) {
            const unwatch = vnode.$watch(() => vnode.$refs.suggestions.showPopper, function () {
              unwatch()
              vnode.$emit('change', val)
            })
            vnode.$once('select', item => {
              unwatch()
              vnode.$emit('change', item[vnode.valueKey])
            })
          } else {
            vnode.$emit('change', val)
          }
        })
      }
    }
  },

剧终

当然如果发现代码仍有BUG,欢迎指出

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值