废话不多说(主要文笔比较差),直接上代码

一个简单的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();
                tempImg.setAttribute('crossOrigin', 'Anonymous');
                tempImg.src = this.imgResize;
                console.log('*****************');
                tempImg.onload = (ev) => {
                    console.log('onload', ev);                
                    console.log('ev.target',ev.target);
                    setTimeout(() => {
                        console.log('settimeout---target:',ev.target) // <- HTMLElement
                    }, 0)
}

输出结果如图

是不是有点奇怪,上面明明说.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的奇怪问题探讨的更多相关文章

  1. android中ListView控件&&onItemClick事件中获取listView传递的数据

    http://blog.csdn.net/aben_2005/article/details/6592205 本文转载自:android中ListView控件&&onItemClick ...

  2. VS中Dev控件在工具箱里的不见的解决办法

    出现问题:调整了VS中Dev控件后(以免生成程序每次都要在客户机上面注册dev),之前安装的DEV控件在vs工具箱中消失了,重装可以解决,但是太费时间了,检测dev自带的设置,找到了解决办法. 解决办 ...

  3. C# 中删除控件的事件的方法类

    方法一: 代码 /// <summary> /// 删除指定控件的指定事件 /// </summary> /// <param name="control&qu ...

  4. vue中时间控件绑定多个输入框

    首先去下载laydate时间控件,引入到相应的模板中 <input type="text" val-required="" value="&qu ...

  5. .net dataGridView当鼠标经过时当前行背景色变色;然后【给GridView增加单击行事件,并获取单击行的数据填充到页面中的控件中】

    1.首先在前台dataGridview属性中增加onRowDataBound属性事件 2.然后在后台Observing_RowDataBound事件中增加代码 protected void Obser ...

  6. VB中WinSock控件的属性、方法、事件及应用

    一.WinSock简介       Socket(套接字)最初是由加利福尼亚大学Berkeley(伯克利)分校为UNIX操作系统开发的网络通信接口,随着UNIX的广泛使用,Socket成为当前最流行的 ...

  7. WinForm中动态添加控件 出现事件混乱,解决办法记录。

    还是在抢票软件中出的问题,我没点击一个联系人,要生成一排控件,其中有席别combobox这样的下拉框控件,会出现如下图所示的问题:问题描述:在代码中动态创建的控件,事件混乱了,一个控件触发了所有同类型 ...

  8. GridView控件RowDataBound事件中获取列字段值的几种途径

    前台: <asp:TemplateField HeaderText="充值总额|账号余额"> <ItemTemplate> <asp:Label ID ...

  9. android中RecyclerView控件实现点击事件

    RecyclerView控件实现点击事件跟ListView控件不同,并没有提供类似setOnItemClickListener()这样的注册监听器方法,而是需要自己给子项具体的注册点击事件. 本文的例 ...

  10. C# winform中自定义用户控件 然后在页面中调用用户控件的事件

    下面是用户控件的代码: using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...

随机推荐

  1. WPF 多线程下跨线程处理 ObservableCollection 数据

    本文告诉大家几个不同的方法在 WPF 里,使用多线程修改或创建 ObservableCollection 列表的数据 需要明确的是 WPF 框架下,非 UI 线程直接或间接访问 UI 是不合法的,设计 ...

  2. 2019-8-31-C#-自动翻页-PPT-测试脚本

    title author date CreateTime categories C# 自动翻页 PPT 测试脚本 lindexi 2019-08-31 16:55:58 +0800 2019-08-1 ...

  3. Ubuntu的apt-get/yarm/wget命令详解

    目录 一.查看本机是否安装软件 二.apt-get 三.yum 四.wget apt-cache和apt-get是apt包的管理工具, 他们根据/etc/apt/sources.list里的软件源地址 ...

  4. csapp-datalab(菜鸟小白版)

    第1题: /* * bitXor - x^y using only ~ and & * Example: bitXor(4, 5) = 1 * Legal ops: ~ & * Max ...

  5. 4G LTE/EPC UE 的附着与去附着

    目录 文章目录 目录 UE 附着 UE 与 MME 建立 NAS 连接 UE 附着协议全景 UE 附着流程 UE 去附着 UE 侧发起的去附着 MME 发起的去附着 HSS 发起的去附着 UE 附着 ...

  6. mogodb replication set复制集

    replication set复制集 简要命令 replication set复制集 replicattion set 多台服务器维护相同的数据副本,提高服务器的可用性. Replication se ...

  7. 新一代AI搜索引擎神器推荐及效果测试:秘塔AI、天工AI、Perplexity等

    新一代AI搜索引擎神器推荐效果测试:秘塔AI.天工AI.Perplexity等 0.前言: 搜索的核心:事物对象级别的搜索 回到搜索引擎本身,搜索引擎的早期出现是为了解决互联网上信息过载的问题.随着互 ...

  8. npm 安装 sass 引用

    1.npm install node-sass --save-dev 2.npm install sass-loader --save-dev npm i less-loader  --save-de ...

  9. 不关闭SELinux情况下使用ftp传输

    在做搭建ftp服务器的作业时,整了一个活,在不关闭SELinux的情况下测试ftp服务器 使用的环境,虚拟机*2 (CentOS 7),Hyper-v,网卡已设为静态 需要安装的软件包: 服务器(下称 ...

  10. HashMap设置初始容量一直都用错了?

    1 背景 今天在代码审查的时候,发现一位离职的同事留下了这样一串代码: Map<String,String> map = new HashMap<>((int)(list.si ...