关于vue中image控件,onload事件里,event.target 为null的奇怪问题探讨
废话不多说(主要文笔比较差),直接上代码
一个简单的demo,如下
<img :src="orginalImgSrc" style="display: none;" crossOrigin="Anonymous" @load="imgLoaded">
vue代码
imgLoaded(e) {
debugger
console.log('event',e);
console.log('target',e.target);
return;
}
这时候,会发现
console.log里的event对象,target始终为null,但是如果debugger进去看,又是可以看到taget对象的
下图为debugger模式下:

下面为控制台

可以清晰的看到,控制台的输出里,target对象始终为null,由于我一开始只输出了event对象,看到target对象为null后百思不得其解,认定从这里取target对象,必然也是null
实际上此处是可以直接获取到target对象的.
那么为什么呢?
参考相关资料后得知
这个问题是事件循环机制导致的,在JavaScript中,事件处理程序是在事件循环任务队列中异步执行的.
但@load事件触发的时候,event事件对象会被正确传递给事件处理程序,demo中为imgLoaded(e),在控制台输出之前,JavaScript引擎已经执行了后续的代码.
但是在这个过程中,某些浏览器优化或者垃圾回收机制导致e.target引用被移除或者清除了,导致第一次打印e.target的时候,显示为null
第二次打印的时候.e.target是一条新的一句,JavaScript的引擎会重新计算e.target的值,所以又获取到了正确的元素引用.
因此通常建议在程序开头,将e.target存储到一个局部变量中.然后再后续的代码中使用该变量,防止JavaScript的引擎执行机制丢失对目标元素的引用
再举个例子,会被优化掉target的例子
const tempImg = new Image();
输出结果如图

是不是有点奇怪,上面明明说.e.target应该会重新计算的,为什么在settimeout里,并没有重新计算呢?
当 onload 事件触发时,ev 参数就是一个指向事件对象的引用。但是,一旦事件处理程序执行完毕,这个引用就会被清除,以节省内存。
在你的代码中,setTimeout 函数会在当前执行上下文结束后,将其回调函数加入事件循环队列。当事件循环再次运行时,它会从事件队列中取出回调函数并执行。
问题在于,当 setTimeout 的回调函数执行时,原始的事件对象 ev 已经不存在了,因此 ev.target 自然就变成了 null。
这个问题在基于 Blink 内核的浏览器中尤其常见,如 Chrome、Edge 等。它们会在事件处理程序执行完毕后,主动清除对事件对象的引用,以优化内存使用。
但是,如果我在setTimeOut里输出ev也就是event对象呢?event对象依然有,只不过target还是null,为什么呢?
这是因为事件对象的生命周期与目标元素的引用生命周期不同。
在 Web 浏览器中,事件对象 ev 本身是一个对象,它包含了许多属性,如 type、currentTarget 等,用于描述事件的细节。但其中的 target 属性指向触发该事件的 DOM 元素。
当事件处理程序执行完毕后,浏览器会清除对目标元素 (ev.target) 的引用,以释放内存。但事件对象 ev 本身并不会被立即销毁,它可能还会在其他地方被使用或引用。
所以在代码中,当 setTimeout 回调函数执行时,虽然 ev.target 已经变成了 null,但 ev 对象本身仍然存在,只是它的 target 属性已经被清除了。这就解释了为什么 console.log('settimeout---ev:', ev) 能够打印出事件对象,但 ev.target 却是 null。
这种行为是浏览器的优化机制,它只清除了对目标元素的引用,而保留了事件对象本身,以防止意外地破坏了其他依赖于该事件对象的代码。
总的来说,在异步操作中访问事件对象的属性时,最安全的做法是将需要使用的属性值提前存储到其他变量中,而不是直接引用事件对象的属性,因为这些属性的生命周期可能会比事件对象本身更短。
所以如果用局部变量接收,就可以正确输出,代码如下
const tempImg = new Image();
tempImg.setAttribute('crossOrigin', 'Anonymous');
tempImg.src = this.imgResize; console.log('*****************');
tempImg.onload = (ev) => {
console.log('onload', ev);
console.log('ev.target',ev.target);
const t_target=ev.target;
setTimeout(() => {
console.log('settimeout---target:',t_target) // <- HTMLElement
}, 0)

参考相关资料:
1 https://github.com/vuejs/vue/issues/7027
2 https://claude.ai/
关于vue中image控件,onload事件里,event.target 为null的奇怪问题探讨的更多相关文章
- android中ListView控件&&onItemClick事件中获取listView传递的数据
http://blog.csdn.net/aben_2005/article/details/6592205 本文转载自:android中ListView控件&&onItemClick ...
- VS中Dev控件在工具箱里的不见的解决办法
出现问题:调整了VS中Dev控件后(以免生成程序每次都要在客户机上面注册dev),之前安装的DEV控件在vs工具箱中消失了,重装可以解决,但是太费时间了,检测dev自带的设置,找到了解决办法. 解决办 ...
- C# 中删除控件的事件的方法类
方法一: 代码 /// <summary> /// 删除指定控件的指定事件 /// </summary> /// <param name="control&qu ...
- vue中时间控件绑定多个输入框
首先去下载laydate时间控件,引入到相应的模板中 <input type="text" val-required="" value="&qu ...
- .net dataGridView当鼠标经过时当前行背景色变色;然后【给GridView增加单击行事件,并获取单击行的数据填充到页面中的控件中】
1.首先在前台dataGridview属性中增加onRowDataBound属性事件 2.然后在后台Observing_RowDataBound事件中增加代码 protected void Obser ...
- VB中WinSock控件的属性、方法、事件及应用
一.WinSock简介 Socket(套接字)最初是由加利福尼亚大学Berkeley(伯克利)分校为UNIX操作系统开发的网络通信接口,随着UNIX的广泛使用,Socket成为当前最流行的 ...
- WinForm中动态添加控件 出现事件混乱,解决办法记录。
还是在抢票软件中出的问题,我没点击一个联系人,要生成一排控件,其中有席别combobox这样的下拉框控件,会出现如下图所示的问题:问题描述:在代码中动态创建的控件,事件混乱了,一个控件触发了所有同类型 ...
- GridView控件RowDataBound事件中获取列字段值的几种途径
前台: <asp:TemplateField HeaderText="充值总额|账号余额"> <ItemTemplate> <asp:Label ID ...
- android中RecyclerView控件实现点击事件
RecyclerView控件实现点击事件跟ListView控件不同,并没有提供类似setOnItemClickListener()这样的注册监听器方法,而是需要自己给子项具体的注册点击事件. 本文的例 ...
- C# winform中自定义用户控件 然后在页面中调用用户控件的事件
下面是用户控件的代码: using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...
随机推荐
- Total Commander 使用 mklink 建立文件夹链接 将 C 盘文件迁移到其他盘
在安装完成了 100000000 个软件之后,我 1T 的 C 盘的空间终于不足了,由于安装了大量的特别挑的不专业的软件,强行放在其他的盘将水土不服.于是在老师傅的指导下,我采用了 mklink 神奇 ...
- dotnet 使用 IndentedTextWriter 辅助生成代码时生成带缩进的内容
随着源代码生成的越来越多的应用,自然也遇到了越来越多开发上的坑,例如源代码的缩进是一个绕不过去的问题.如果源代码生成是人类可见的代码,我期望生成的代码最好是比较符合人类编写代码的规范.为了能让人类在阅 ...
- Vue源码-手写mustache源码
引言 在Vue中使用模板语法能够非常方便的将数据绑定到视图中,使得在开发中可以更好的聚焦到业务逻辑的开发. mustache是一个很经典且优秀的模板引擎,vue中的模板引擎也对其有参考借鉴,了解它能更 ...
- 七、Doris Colocation Join
Colocation Join 是在 Doris 0.9 版本中引入的新功能.旨在为某些 Join 查询提供本地性优化,来减少数据在节点间的传输耗时,加速查询. 1.基本理论 Join 的常见连接类型 ...
- Gparted扩展硬盘空间
需求:有一些磁盘占满了空间,例如/亦或者/opt目录等.可以通过Gparted扩展空间. 1.vmware添加ISO [添加光盘]gparted-live-cd添加至ISO 2.延迟引导启动,强制进入 ...
- 01.windows 环境设置
windows下可以安装Git工具, 使用git bash操作 Windows 10 环境下,通过-/.bash_profile 设置 git bash 别名: 打开 git bash,需切换到当前用 ...
- RemoteView 替代品和类似软件
RemoteView 是一款远程控制软件,使您可以通过Internet连接远程访问计算机和移动设备,而不受时间和地点的限制. 您可以快速,安全地实时轻松地控制计算机和移动设备. 您可以使用我们的iOS ...
- Web3连接以太网
1. Infura Infura 是一种托管服务,提供对各种区块链网络的安全可靠访问,消除了管理区块链基础设施的复杂性,使开发者能够专注于构建创新的 Web3 应用程序. Infura 作为连接应用程 ...
- java学习之旅(day.08)
类与对象的关系 类是一种抽象的数据类型,是对某一类事物的描述,但并不代表具体的事物,如动物与狗的关系,类描述的是某一类事物具备的共同特点 对象是抽象概念的具体实例 能够展现出功能,体现出特点的是具体的 ...
- hadoop部署2
完全分布式部署介绍 学习目标 完全分部式是真正利用多台Linux主机来进行部署Hadoop,对Linux机器集群进行规划,使得Hadoop各个模块分别 部署在不同的多台机器上. 能够了解完全分布式部署 ...