解决Vue自定义多选组件中Blur事件失效问题:Focusout的妙用

解决Vue自定义多选组件中Blur事件失效问题:Focusout的妙用

vue自定义多选组件中,当组件内部包含可聚焦元素(如输入框)时,直接在父容器上使用`blur`事件可能无法按预期触发,导致组件失去焦点时无法执行相应逻辑(例如关闭选项列表)。本文将深入解析`blur`事件不冒泡的特性,并提出使用`focusout`事件作为替代方案,详细阐述其工作原理及在复杂组件中实现正确焦点管理的方法。

理解Blur与Focusout事件

在Web开发中,处理用户界面焦点变化是常见的需求,尤其是在构建复杂的自定义组件时。blur和focusout是两种与元素失去焦点相关的事件,但它们在行为上存在关键差异:

blur事件:当一个元素本身失去焦点时触发。这个事件不会冒泡。这意味着,如果你在一个父元素上监听blur事件,但焦点从其子元素转移到父元素外部,父元素上的blur事件不会被触发。在多选组件的场景中,如果用户点击了组件内的输入框,然后点击组件外部,由于输入框失去焦点时blur事件不会冒泡到外层容器,导致父容器无法感知到焦点已离开整个组件。

focusout事件:当一个元素或其任何后代元素失去焦点时触发。这个事件会冒泡。这意味着,即使是子元素失去了焦点,focusout事件也会沿着DOM树向上冒泡,直到根元素。这使得focusout成为在父容器上监听整个组件焦点状态变化的理想选择。

原始问题分析

考虑一个自定义的多选组件,其结构包含一个外部div用于包裹整个组件,内部有输入框、已选选项列表和待选选项列表。组件希望在用户点击组件外部时关闭选项列表。最初的实现可能尝试在外部div上使用@blur=”showOptions = false”:

立即学习“前端免费学习笔记(深入)”;

<!-- ... 组件内部结构,包括一个 元素 ... -->

然而,这种实现会遇到一个问题:如果用户首先点击了组件内的input输入框,然后再点击组件外部的任何地方,外部div上的blur事件并不会被触发。这是因为当input失去焦点时,其blur事件不会冒泡到父div。因此,showOptions状态不会被更新,选项列表会保持打开状态。

解决方案:使用Focusout事件

为了解决blur事件不冒泡的问题,我们可以将外部div上的@blur事件替换为@focusout事件。focusout事件的冒泡特性使其能够捕获到组件内部任何子元素失去焦点的事件,并将其传递给父容器。

修正后的代码示例:

  
{{ label }}
{{ option.text }}
  • {{ option.text }}
No records found
import { defineComponent, PropType, ref, watch } from "vue";import { IconNameTypes } from "@/types/enums/IconNameTypes";import { AppIcon } from "@/components/base/index";import { MagnifyingGlassIcon } from "@heroicons/vue/24/outline";export default defineComponent({ name: "AppAutocomplete", components: { AppIcon, MagnifyingGlassIcon, }, props: { modelValue: { type: String, }, label: { type: String, default: "", }, tabIndex: { type: Number, default: 0, // 确保 tabIndex 存在且有效 }, options: { type: Array as PropType, required: true, }, }, setup(props, { emit }) { const showOptions = ref(false); const optionsMap = ref(props.options); const selectedOptions = ref([]); const searchInput = ref(""); watch(searchInput, () => { optionsMap.value = props.options.filter((option1) => { return ( !selectedOptions.value.some((option2) => { return option1.text === option2.text; }) && option1.text.toLowerCase().includes(searchInput.value.toLowerCase()) ); }); sortOptionsMapList(); }); const onOptionClick = (option: { text: string; value: string }) => { searchInput.value = ""; selectedOptions.value.push(option); optionsMap.value = optionsMap.value.filter((option1) => { return !selectedOptions.value.some((option2) => { return option1.text === option2.text; }); }); sortOptionsMapList(); emit("update:modelValue", option.value); }; const onDeleteOption = (option: { text: string; value: string }) => { selectedOptions.value = selectedOptions.value.filter((option2) => { return option2.text !== option.text; }); optionsMap.value.push(option); sortOptionsMapList(); }; const sortOptionsMapList = () => { optionsMap.value.sort(function (a, b) { return a.text.localeCompare(b.text); }); }; sortOptionsMapList(); // 移除不必要的 document.addEventListener("click"),因为它会干扰组件内部的焦点管理 // document.addEventListener("click", () => { // console.log(document.activeElement); // }); return { showOptions, optionsMap, searchInput, selectedOptions, IconNameTypes, onOptionClick, onDeleteOption, }; },});.options-list,#not-found { box-shadow: 0 0 50px 0 rgb(19 19 28 / 12%); @apply border border-[#EAEAEA] rounded-md p-4 mt-1 absolute bg-white z-10 w-full;}ul { @apply max-h-52 #{!important};}

在上述代码中,关键的改动是将@blur=”showOptions = false”修改为@focusout=”showOptions = false”。现在,无论用户是直接点击了父div外部,还是先点击了组件内的input,然后将焦点移出组件,focusout事件都会在父div上触发,从而正确地关闭选项列表。

tabindex属性的重要性

在上述解决方案中,父div上使用了:tabindex=”tabIndex”属性。tabindex属性在这里扮演了重要角色:

使非交互元素可聚焦:默认情况下,div元素是不可聚焦的。tabindex属性允许将任何HTML元素设置为可聚焦,使其可以通过键盘(Tab键)进行导航。确保focusout在父元素上生效:为了让父div能够接收到焦点事件(包括focusout),它本身必须是可聚焦的。通过设置tabindex=”0″(或任何非负整数),我们确保了div可以接收焦点,从而能够正确地监听和响应focusout事件。

注意事项与最佳实践

事件冒泡与捕获:理解事件冒泡和捕获机制是处理DOM事件的关键。focusout事件利用了冒泡阶段来向上通知父元素。mousedown vs click:在选项列表的li元素上,使用了@mousedown而不是@click。这是为了确保在选项被点击时,focusout事件不会过早地触发并关闭列表。mousedown事件在focusout之前触发,允许我们处理选项选择逻辑,然后才处理焦点离开组件的逻辑。避免全局监听:在原始代码中,有一个document.addEventListener(“click”, …)的全局监听器。在大多数情况下,对于组件内部的焦点管理,应尽量避免这种全局监听,因为它可能与组件自身的事件处理逻辑冲突,导致难以调试的问题。focusout事件提供了一种更局部化和高效的解决方案。可访问性(Accessibility):正确使用tabindex和焦点管理对于确保组件的可访问性至关重要,特别是对于依赖键盘导航的用户。

总结

在Vue自定义组件中,当需要检测整个组件何时失去焦点时,blur事件因其不冒泡的特性而无法满足需求。通过将事件监听从@blur切换到@focusout,并确保父容器具有tabindex属性使其可聚焦,我们可以有效地实现组件的焦点管理。focusout事件的冒泡机制使其成为处理复杂交互式组件焦点状态变化的强大而可靠的工具,从而提升用户体验和组件的健壮性。

以上就是解决Vue自定义多选组件中Blur事件失效问题:Focusout的妙用的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1591753.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月23日 07:06:21
下一篇 2025年12月23日 07:06:34

相关推荐

  • 手把手教你使用css给文字添加火焰效果(代码详解)

    之前的文章《一招教你使用html给图片添加边框效果(代码详解)》中,给大家介绍了怎么使用html给图片添加边框效果。下面本篇文章给大家介绍怎么使用css给文字添加火焰效果,我们一起看看怎么做。 打开HTML代码软件,建立一个代码 1、这儿来一个p标签,然后咱就随便写几个,开心就笑,累了就睡觉,醒了就…

    2025年12月24日 好文分享
    000
  • 手把手教你怎么使用css3给文字添加动画效果(附代码)

    之前的文章《手把手教你使用css给文字添加火焰效果(代码详解)》中,给大家介绍了怎么使用css给文字添加火焰效果。下面本篇文章给大家介绍怎么使用css3给文字添加动画效果,我们一起看看怎么做。 在这类网站中能看到,无论是文字还是图片,都随着规定时间的而变化。css3的主键强大原理很简单,主要用到cs…

    2025年12月24日
    000
  • 手把手教你使用css制作一个简单的心跳效果(代码详解)

    之前的文章《手把手教你怎么使用css3给文字添加动画效果(附代码)》中,给大家介绍怎么使用css3给文字添加动画效果。下面本篇给大家介绍怎么使用css制作一个简单的心跳效果,我们一起看看怎么做。 ccs制作一个简单的心跳效果的方法,添加一个盒子,充分利用ccs展现就可以啦。 1、首先我们在页面添加一…

    2025年12月24日
    000
  • 很实用!CSS实现在单击按钮时显示按下的动态效果

    在上一篇《如何用css快速创建3点加载动画》中给大家介绍了如何用css创建3点加载动画效果,感兴趣的朋友可以去阅读了解一下~ 本文将给大家介绍在前端设计过程中非常实用的一个动态效果,就是在单击按钮时显示按下的动态效果,光说可能大家还不明白是什么效果,我们可以直接看一个动图: 不过本文不仅会介绍实现这…

    2025年12月24日
    000
  • 手把手教你使用css3给文字添加阴影效果(代码详解)

    之前的文章《CSS篇:如何将页面背景设置渐变效果(代码详解)》中,给大家介绍了怎样使用css设置背景色渐变。下面本篇文章给大家介绍怎样使用css3给文字添加阴影效果呢,我们一起看看怎么做。 用css3给文字添加阴影效果代码示例 文字阴影 h1{text-shadow: 7px 10px 6px #F…

    2025年12月24日 好文分享
    200
  • css怎么给文字添加边框或字体放大效果(代码详解)

    之前的文章《手把手教你使用css3给文字添加阴影效果(代码详解)》中,给大家介绍了怎样使用cs3给文字添加阴影效果。下面本篇文章给大家介绍怎样使用css给文字添加边框或字体放大效果,我们一起看看怎么做。 css给文字加添边框或字体放大的方法 文字边框 p{ border:2px solid blue…

    2025年12月24日 好文分享
    000
  • 一步步教你使用CSS制作一个简单美观的导航栏(代码详解)

    之前的文章《css怎么给文字添加边框或字体放大效果(代码详解)》中,给大家介绍了怎样使用css文字添加边框或字体放大。下面本篇文章给大家介绍如何用CSS制作一个简单美观的导航栏,我们一起看看怎么做。 使用css制作页面的时候,想做一个简单美观的导航栏,怎么做呢,下面来分享一下方法。 导航栏+链接列表…

    2025年12月24日 好文分享
    000
  • 一招搞定css不规则边框

    大家可能都习惯了使用box-shadow来设置盒阴影,但顾名思义,盒阴影一般阴影的投影是一个方形,如果我们遇到其他情况,想要做阴影效果应该怎么实现呢? 之前做过很多特殊的布局,比如在这两篇文章 CSS 实现优惠券的技巧 、CSS 实现支持渐变的提示框(tooltips),如下 但是一直有一个痛点就是…

    2025年12月24日 好文分享
    000
  • 10款好看且实用的文字动画特效,让你的页面更吸引人!

    图片和文字是网页不可缺少的组成部分,图片运用得当可以让网页变得生动,但普通的文字不行。那么就可以给文字添加一些样式,实现一下好看的文字效果,让页面变得更交互,更吸引人。下面创想鸟就来给大家分享10款文字动画特效,好看且实用,快来收藏吧! 1、网页玻璃文字动画特效 模板简介:使用css3制作网页渐变底…

    2025年12月24日 好文分享
    000
  • 如何实现炫酷的数字大屏

    依托强大无远开发平台,可以快速实现带各种酷炫联动效果的数字化大屏。一起来看一下吧 DEMO 地址:https://previewer.wuyuan.io/p… 配置地址:https://workbench.wuyuan.io/p… 效果图 1 效果图 2 实现步骤 1. 完成…

    2025年12月24日 好文分享
    000
  • 手把手教你使用css给HTML字体添加边框效果(代码分享)

    之前的文章《html网页中如何实现居中效果(代码分享)》中,给大家介绍了如何让网页整体居中。下面本篇文章给大家介绍怎样使用css给HTML元素字体添加边框效果,我们一起看看怎么做。 html元素添加边框用border属性来实现。 border 简写属性在一个声明设置所有的边框属性。 border属性…

    2025年12月24日
    000
  • 一招搞定css元素五彩斑斓的背景

    本篇文章将开始新的一个章节。所有好看的事物都离不开颜色,今天我们就来学习一个最简单的,那就是给元素设置背景颜色。快来学习吧。 我们也知道没有背景颜色的元素是不好看的,所有我们还是需要给元素设置背景颜色的。 我们先来看一个小例子吧,了解一下什么是背景颜色,怎么去设置。 已知,我们有一个div元素,一个…

    2025年12月24日
    000
  • 一招教你使用css给HTML字体添加背景图(代码分享)

    之前的文章《手把手教你使用css给HTML字体添加边框效果(代码分享)》中,给大家介绍了怎样使用css给HTML字体添加边框效果。下面本篇文章给大家介绍如何用css给HTML字体添加背景图,我们一起看看怎么做。 先看一下最终实现的效果 如何在字体添加背景图? 1、在html打开中,首先写div标签,…

    2025年12月24日 好文分享
    000
  • 用CSS快速创建高级模糊感的背景图像

    想让你的网页页面显得高级感十足吗?想要提高你网页的阅读访问量吗?想让你的用户一眼就被你的页面吸引住吗?那么就不要错过本文啦!毕竟简单又快速的实现高级感模糊的背景图,谁都可以学会! 废话不多说,开始正文! 正如标题所言我们今天所要介绍的就是通过css来创建一个模糊的背景图像,适用于你个人博客页面,也适…

    2025年12月24日
    000
  • css上边距怎么写

    在css中,可以使用margin-top属性设置上边距,只需要给元素设置“margin-top:数值+单位;”样式即可。margin-top属性设置元素的上外边距,允许使用负值。 本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3电脑。 margin 简写…

    2025年12月24日
    000
  • css中:not用法是什么

    在css中,“:not”是选择器的一种,如果希望某个样式不作用到选择器上,可以使用:not(选择器),语法格式为“ 元素:not(元素id){属性:属性值;}”;该选择器匹配非指定元素/选择器的每个元素。 本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3…

    2025年12月24日
    000
  • css怎么让背景图拉伸

    在css中,可以使用background-size属性让背景图拉伸,只需要给元素设置“background-size:100% 100%;”样式即可。该属性可以以父元素的百分比来设置背景图像的宽度和高度。 本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3…

    2025年12月24日 好文分享
    000
  • 利用CSS如何实现全兼容的毛玻璃效果?(代码详解)

    本篇文章带大家了解一下css backdrop-filter属性,看看该属性的兼容性,介绍一下如何实现全兼容毛玻璃效果。 通过本文,你能了解到 最基本的使用 CSS backdrop-filter 实现磨砂玻璃(毛玻璃)的效果 在至今不兼容 backdrop-filter 的 firefox 浏览器…

    2025年12月24日 好文分享
    000
  • 详解CSS content的使用机制,原来还可以这样用!

    本篇文章带大家了解一下css中的content属性,介绍一下content的使用场景,希望对大家有所帮助! 在开发中遇到类似清除浮动、小图标、替换内容等场景时不可避免会遇到 content 属性,一般就是百度下解决方案,甚少细究到底,在看《CSS 世界》这本书时看了下 content 章节,今天这里…

    2025年12月24日 好文分享
    000
  • CSS怎么设置字体发光效果

    在CSS中,可以利用text-shadow属性来设置字体发光效果;该属性可为文本添加阴影效果,设置阴影的水平偏移量和垂直偏移量为0,增大阴影模糊的距离,即可以达到字体外发光的效果。 本教程操作环境:windows7系统、CSS3&&HTML5版、Dell G3电脑。 在CSS中,可以…

    2025年12月24日
    000

发表回复

登录后才能评论
关注微信