MaterialUI下拉选后输入框保焦实现方式及Vue适配疑问
解决方案
要实现点击下拉项后输入框保持焦点,核心是避免点击下拉项时触发输入框失焦的默认浏览器行为,同时不破坏滚动功能,推荐以下两种方案:
方案一:阻止下拉项的mousedown默认行为(推荐)
这种方式直接拦截下拉项的mousedown默认行为,避免浏览器将焦点从输入框转移到下拉项,且不会影响父容器的滚动(滚动操作由父容器事件处理,与子项的mousedown无关)。
修改app-input-autocomplete组件的模板部分:
<div v-for="result in results" :key="result.id" @mousedown.prevent="onClick(result)" class="input-autocomplete-result"> <slot :result="result" /> </div>
原理说明
浏览器触发元素mousedown时,默认会将焦点转移到该元素,导致输入框失焦。通过@mousedown.prevent阻止这个默认行为,输入框就能保持焦点,同时click事件依然正常触发(preventDefault仅阻止默认行为,不中断事件传播)。
方案二:延迟判断blur事件(兼容场景)
如果方案一存在兼容性问题,可通过设置标志位,在blur事件中延迟判断是否点击了下拉项,若是则重新聚焦输入框。
- 修改模板,添加状态标记并给
app-input添加ref:
<app-input ref="inputRef" @focus="onFocus" @blur="onBlur" v-bind="$attrs"> <template #underInput> <div ref="dropdown" v-show="open" class="input-autocomplete-dropdown"> <div class="input-autocomplete-results"> <div v-for="result in results" :key="result.id" @mousedown="() => isClickingDropdown = true" @mouseup="() => isClickingDropdown = false" @click="onClick(result)" class="input-autocomplete-result"> <slot :result="result" /> </div> </div> </div> </template> </app-input>
- 修改script部分,补充对应逻辑:
setup(props, { emit }) { const dropdown = ref(null); const inputRef = ref(null); const open = toRef(props, 'open'); const focused = ref(false); const isClickingDropdown = ref(false); onClickOutside(dropdown, () => { if (!focused.value && open.value) { emit('autocomplete-close'); } }); return { dropdown, focused, inputRef, isClickingDropdown, }; }, methods: { onFocus() { this.focused = true; }, onBlur() { setTimeout(() => { if (this.isClickingDropdown) { // 获取输入框DOM并重新聚焦 const inputElem = this.$refs.inputRef.$el.querySelector('input'); inputElem?.focus(); this.isClickingDropdown = false; } else { this.focused = false; } }, 0); }, onClick(result) { this.$emit('autocomplete-select', result); }, },
原理说明
点击下拉项时,输入框的blur会先于下拉项的click触发。通过setTimeout延迟执行blur逻辑,此时可通过isClickingDropdown标志判断是否点击了下拉项,若是则重新聚焦输入框。
内容的提问来源于stack exchange,提问作者Tallboy
相关产品推荐
相关产品推荐

