【面试 - el-select问题及解决】wujie 微前端下子系统 el-select 多选 filterable 过滤失效

目录

  • [1. 问题描述](#1. 问题描述)
  • [2. wujie 微前端下 el-select 多选 filterable 过滤失效问题修复](#2. wujie 微前端下 el-select 多选 filterable 过滤失效问题修复)
    • [2.1 问题现象](#2.1 问题现象)
    • [2.2 根因分析](#2.2 根因分析)
      • [2.2.1 问题一:事件对象在防抖延迟期间失效](#2.2.1 问题一:事件对象在防抖延迟期间失效)
      • [2.2.2 问题二:isOnComposition 状态被错误锁定](#2.2.2 问题二:isOnComposition 状态被错误锁定)
    • [2.3 解决方案](#2.3 解决方案)
    • [2.4 修复原理](#2.4 修复原理)
    • [2.5 适用范围](#2.5 适用范围)
    • [2.6 相关文件](#2.6 相关文件)

1. 问题描述

  • 系统A 单独运行的时候 select下拉数据不论多选还是单选,filter 过滤都正常,
  • 但是系统A通过 wujie 的方式嵌到系统B时,
    • 系统A单选的 select 使用 filter 过滤时正常,
    • 多选的 select 使用 filter 过滤时下拉数据没有变(没有触发过滤),
  • 这是为什么?怎么解决

2. wujie 微前端下 el-select 多选 filterable 过滤失效问题修复

2.1 问题现象

环境 单选 + filterable 多选 + filterable
独立运行 正常 正常
wujie 嵌入 正常 失效(输入字母无过滤,输入中文报错)

错误信息:Uncaught TypeError: Cannot read properties of null (reading 'value')

2.2 根因分析

Element UI 的 el-select 在单选 和多选 模式下使用了不同的过滤输入处理路径:

  • 单选模式 :debouncedOnInputChange → 内部读取 this.query(组件响应式数据),不依赖事件对象
  • 多选模式 :debouncedQueryChange → 内部读取 e.target.value(事件对象属性)

debouncedQueryChange 是一个 300ms 防抖函数,在 wujie 沙箱环境中存在两个问题:

2.2.1 问题一:事件对象在防抖延迟期间失效

wujie 会代理/合成事件(isTrusted: false),这些合成事件在 handler 返回后会被回收。300ms 后防抖回调执行时 e.target 已为 null,导致:

  • 输入字母 → 取不到值,过滤不触发
  • 输入中文 → 报错 Cannot read properties of null (reading 'value')

2.2.2 问题二:isOnComposition 状态被错误锁定

wujie 沙箱中多选输入框动态创建时,可能触发 compositionstart 但不触发 compositionend,导致 Element UI 内部 isOnComposition 卡在 true,handleQueryChange 进入后直接 return,过滤逻辑被跳过。

2.3 解决方案

在 src/main.js 的 wujie 补丁块(if (window.$wujie) { ... })中添加以下代码,完全替换 debouncedQueryChange,不依赖 event 对象,改为直接从 DOM 读值:

js 复制代码
if (window.$wujie) {
  const components = ['ElSelect', 'ElDatePicker', 'ElTimePicker', 'ElCascader', 'ElAutocomplete']
  components.forEach((name) => {
    const comp = Vue.component(name)
    if (!comp) return
    Vue.component(name, {
      extends: comp,
      props: {
        popperAppendToBody: { type: Boolean, default: false },
        appendToBody: { type: Boolean, default: false },
        popperClass: { type: [String, Array], default: 'insert-wujie_popper-class' },
        collapseTags: { type: Boolean, default: true }
      }
    })
  })

  // 修复 wujie 环境下多选 el-select filterable 过滤无效问题
  // 根因:debouncedQueryChange 是防抖函数(延迟300ms执行),内部通过 e.target.value 取值,
  // 但 wujie 沙箱中事件对象在防抖延迟期间会被回收/失效(isTrusted:false 的合成事件尤其严重),
  // 导致延迟回调执行时 e.target 已为 null 或值丢失,过滤逻辑不触发或报错
  // 解决:完全不依赖 event 对象,防抖回调内直接从 DOM 读取输入值
  Vue.mixin({
    beforeMount() {
      if (this.$options.name === 'ElSelect' && this.debouncedQueryChange) {
        const vm = this
        this.debouncedQueryChange = debounce(function() {
          // 重置 isOnComposition,防止 wujie 下 compositionend 未触发导致阻塞
          vm.isOnComposition = false
          // 直接从 DOM 读取多选过滤输入框的当前值,不依赖可能已失效的 event 对象
          const input = vm.$el && vm.$el.querySelector('.el-select__input')
          const val = input ? input.value : vm.query || ''
          vm.handleQueryChange(val)
        }, 300)
      }
    }
  })
}

注意:debounce 来自项目已引入的 lodash.debounce

2.4 修复原理

复制代码
用户输入 → input 事件触发 debouncedQueryChange()
                    ↓
            [等待 300ms 防抖]
                    ↓
        ┌─── 原始方案(失效)────┐     ┌─── 新方案(可靠)─────┐
        │ 读 e.target.value      │     │ 读 DOM input.value     │
        │ (事件已被 wujie 回收)  │     │ (DOM 元素始终存在)     │
        │ → null → 报错/无值     │     │ → 取到正确输入值       │
        └────────────────────────┘     └────────────────────────┘
                                                ↓
                                    vm.isOnComposition = false
                                                ↓
                                    vm.handleQueryChange(val) → 过滤生效 ✓

2.5 适用范围

所有使用 Element UI 2.x + wujie 微前端 的项目,只要出现多选 select 过滤失效的问题,都可以使用此方案修复。

2.6 相关文件

  • 修复位置:src/main.js(wujie 补丁块内)
  • 影响组件:所有使用 el-select + multiple + filterable 的页面
相关推荐
brien942 分钟前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance1 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M1 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写1 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李1 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易1 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马2 小时前
前沿视界
前端
kyriewen2 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易2 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员
IT_陈寒2 小时前
Vue的这个响应式陷阱,差点让我加班到天亮
前端·人工智能·后端