js使用proxy代理监听控制事件

 本文为proxy代理的实例应用,有关代理的内容可以参考:

js语法---理解反射Reflect对象和代理Proxy对象

 监听事件

要监听dom元素的事件,我们会采用回调触发的方式来执行操作,

而触发事件的过程很明显是一个异步操作,异步操作可以使用回调执行,

除此之外,异步操作也可以使用promise来执行,

也就是说,触发一个事件就是完成一个promise

而完成一个promise就执行一个操作,这样就完成了对一个事件一次监听

模拟按钮点击事件

我们需要提供一个方法获取一个proxy代理对象,它会拦截事件属性,并返回一个promise,这个事件触发时,promise完成,然后由于事件是可以多次触发的(点击一次触发一次),我们就需要循环监听,每次拦截事件,都有返回一个新的promise,并等待,

(async()=>{// 获得元素实例,const btn = getElement('button')while(1){//循环监听事件// 等待事件触发await btn.waitClick;// 执行操作console.log('click')}
})()

通过getElement方法拿到元素的代理对象,然后设置一个无限循环,每次循环都要等待代理对象的waitClick属性,这个属性会返回一个promise等待点击事件的完成,当我们点击了按钮之后,执行一个操作,然后进入下一次循环,继续等待点击

 实现getElement方法

const getElement = (element)=>{const dom = document.querySelector(element);// 使用代理拦截访问器,捕获属性const proxy = new Proxy(dom,{get(target,key){if(key === 'waitClick'){//捕获waitClick属性return new Promise((res)=>{// 返回promisedom.addEventListener('click',res,{once:true});//当按钮监听到click事件,执行res,让promise完成,只触发一次})}}})// 代理对象的功能: 拦截对象的访问---访问对象,访问属性,拦截对象的设置---设置属性和值,// 拦截表示可以添加额外的处理,操作属性名,属性值return proxy;
}

注意:每次点击按钮都只触发一次事件,完成一个promise,而下一次循环访问waitClick属性时,又会返回一个新的promise等待按钮点击,

可以看到我们点击了按钮11次,就执行了11次打印,这样就相当于onclick属性的回调,

但是不同的是,我们可以对每一次的事件触发都进行捕获,控制每一次事件的执行,

比如说控制事件总共能监听的次数,对不同的次数执行不同的操作,

(async()=>{// 获得元素实例,const btn = getElement('button')let x = 0;while(x<10){//循环监听事件// 等待事件触发await btn.waitClick;// 执行操作console.log(`第${x+1}次点击`);x++;}
})()

这里就只能触发10次事件,每次事件监听都可以区分开,

优化代理

上面的代理方式只能触发一个click事件,但是在dom元素中,事件是非常多的,要让它能监听多个事件,不该是去一个一个的添加属性捕获,

可以优化拦截捕获,这里采用的是wait+事件名称的属性名,只需要去将wait开头的事件名提取出来,进行监听,

const getElement = (element)=>{const dom = document.querySelector(element);// 使用代理拦截访问器,捕获事件const proxy = new Proxy(dom,{get(target,key){if(!key.startsWith('wait')){//如果属性名没有wait开头return Reflect.get(target,key);//返回原属性}else{const eventName = key.replace('wait','').toLowerCase();//去掉wait然后将属性名开头小写return new Promise((res)=>{ dom.addEventListener(eventName,res,{once:true})   //事件触发时,promise执行成功,只触发一次})}}})// 代理对象的功能: 拦截对象的访问---访问对象,访问属性,拦截对象的设置---设置属性和值,// 拦截表示可以添加额外的处理,操作属性名,属性值return proxy;
}

这里会监听所有以wait开头的属性,并且触发对应的事件

(async () => {// 获得元素实例,const body = getElement('body')let x = 0;while (x < 5) {//循环监听事件// 等待事件触发await body.waitKeydown;// 执行操作console.log(`第${x + 1}次按下键盘`);x++;}
})()

这里可以监听5次键盘按下,这样就实现了任意事件的监听,

tips:当然以上的操作都可以使用回调的方式监听,而且性能会高于这里的循环等待,这里只是展示proxy的用法,实际开发中事件的监听还是采用回调的方式是最优解,

完整代码展示 

// 消除事件监听的回调,无限循环中,等待事件触发再执行操作const getElement = (element) => {const dom = document.querySelector(element);// 使用代理拦截访问器,捕获事件const proxy = new Proxy(dom, {get(target, key) {if (!key.startsWith('wait')) {//如果属性名没有wait开头return Reflect.get(target, key);//返回原属性} else {const eventName = key.replace('wait', '').toLowerCase();//去掉wait然后将属性名开头小写return new Promise((res) => {dom.addEventListener(eventName, res, { once: true })   //事件触发时,promise执行成功,只触发一次})}}})// 代理对象的功能: 拦截对象的访问---访问对象,访问属性,拦截对象的设置---设置属性和值,// 拦截表示可以添加额外的处理,操作属性名,属性值return proxy;
}(async () => {// 获得元素实例,const body = getElement('body')let x = 0;while (x < 5) {//循环监听事件// 等待事件触发await body.waitKeydown;// 执行操作console.log(`第${x + 1}次按下键盘`);x++;}
})()// const getElement = (element)=>{
//   const dom = document.querySelector(element);//   // 使用代理拦截访问器,捕获属性
//   const proxy = new Proxy(dom,{
//     get(target,key){
//       if(key === 'waitClick'){//捕获waitClick属性
//         return new Promise((res)=>{// 返回promise
//           dom.addEventListener('click',res,{once:true});//当按钮监听到click事件,执行res,让promise完成,只触发一次
//         })
//       }
//     }
//   })
//   // 代理对象的功能: 拦截对象的访问---访问对象,访问属性,拦截对象的设置---设置属性和值,
//   // 拦截表示可以添加额外的处理,操作属性名,属性值
//   return proxy;
// }// (async()=>{
//   // 获得元素实例,
//   const btn = getElement('button')
//   let x = 0;
//   while(x<10){//循环监听事件
//     // 等待事件触发
//     await btn.waitClick;
//     // 执行操作
//     console.log(`第${x+1}次点击`);
//     x++;
//   }
// })()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/42406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker 使用基础(1)—镜像仓库

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 4:20 &#x1f504; ◀️ ⏸ …

Pinia在vue项目中的使用

Pinia是Vue 3官方推荐的状态管理模式&#xff0c;由尤雨溪创建并集成到了 Vue.js 中&#xff0c;它是一个轻量级、纯粹基于函数的思想实现的应用状态管理库。Pinia的设计理念类似于Redux&#xff0c;但它更简单易用&#xff0c;更适合于小型到中型的单文件组件应用。 在Vue 3项…

android13 固定U盘链接 SD卡链接 TF卡链接 硬盘链接

1.前言 有些客户使用的应用并不带有自动监听U盘 sd卡广播的代码,使用的代码是固定的地址,这样的话,就需要我们将系统的挂载目录固定了。 原始路径 /storage/3123-19FA 增加链接 /storage/upan_000 -> /storage/3123-19FA 2. 首先如果是应用本身监听的话,使用的是 /…

【Linux线程篇】探索Linux多线程:并行编程的入门指南

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; Linux线程概念 什么是线程 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”一切进程至少都有一个执行线程线程在进程内部运行&am…

【国产开源可视化引擎Meta2d.js】数据

数据 Meta2d.js是由数据驱动显示的。图纸和图元支持任意数据。 内置属性 基于“约定优于配置”原则&#xff0c;Meta2d.js引擎会有一些内置属性名&#xff0c;例如id表示唯一标识、name表示图元名称、text表示文本、color表示颜色等。 内置属性有固定含义&#xff0c;影响显…

揭秘:离心风机风量背后的科学原理

在工业生产和建筑环境中&#xff0c;离心风机如同一位不倦的呼吸管家&#xff0c;默默地维持着空气流动与品质。 你是否好奇过&#xff0c;究竟是什么因素在背后操纵着这位“呼吸管家”的风量表现呢&#xff1f;今天&#xff0c;就让我们一探究竟。 举个例子&#xff1a;你在吹…

『大模型笔记』GraphRAG:利用复杂信息进行发现的新方法!

GraphRAG:利用复杂信息进行发现的新方法! 文章目录 一. GraphRAG:利用复杂信息进行发现的新方法!1. 将RAG应用于私人数据集2. 整个数据集的推理3. 创建LLM生成的知识图谱4. 结果指标5. 下一步二. 参考文献微软官方推文:https://www.microsoft.com/en-us/research/blog/gra…

LeetCode题练习与总结:反转字符串中的单词--151

一、题目描述 给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;输入字符串 s中可能会存在…

速盾:好的cdn服务器

CDN&#xff08;Content Delivery Network&#xff09;是指内容分发网络&#xff0c;是一种将网站的静态内容&#xff08;如图片、音频、视频&#xff09;缓存在分布式的服务器节点上&#xff0c;通过就近访问用户的请求&#xff0c;提供快速可靠的内容传输服务的技术。 好的C…

HTML5文本标签、图像标签、超链接

一、文本样式标签 字体样式标签&#xff1a; 加粗&#xff1a;<strong>…</strong> 斜体&#xff1a; < em >…</ em> eg&#xff1a; <h3>徐志摩人物简介</h3> <p> <strong>1910</strong>年入杭州学堂<br/> &l…

微信小程序 - 本地存储 增加有效期

小程序的本地存储API提供了wx.setStorageSync和wx.setStorage来存储数据&#xff0c;注意的是&#xff0c;小程序的本地存储并没有明确的有效期设置&#xff0c;存储的数据在不超过限制的情况下&#xff0c;会一直保留。 一、小程序本地存储API 小程序的本地存储API提供了设置…

WEB06JavaScriptAjax

基础语法 引入方式 引入方式 内部脚本&#xff1a;将JS代码定义在HTML页面中 JavaScript代码必须位于<script></script>标签之间 在HTML文档中&#xff0c;可以在任意地方&#xff0c;放置任意数量的<script> 一般会把脚本置于<body>元素的底部&a…

常见的气体流量计有哪些?

1.气体涡轮流量计 适用场合&#xff1a;流量变化小&#xff0c;脉动流频率小&#xff0c;中低压洁净天然气优点 1.精度高&#xff0c;重复性好 2.测量范围广&#xff0c;压损小&#xff0c;安装维修方便 3.具有较高的抗电磁干扰和抗震动能力缺点&#xff1a;分辨率低&#xff…

活动:不要卷模型,要卷应用

如何理解李彦宏说的“不要卷模型&#xff0c;要卷应用” 1. 现状 现如今&#xff0c;是否具备独立的 AI 技术似乎已经成为衡量一个互联网企业是否成功的标志。各家都在竭尽全力卷模型、卷数据、卷训练效果&#xff0c;市面上仅是语言类 AI 就多达十几种&#xff0c;但从一名消…

浏览器中js外挂脚本的执行方式

1、开发工具控制台交互执行 网页中按F12打开开发者工具&#xff0c;选择“控制台”&#xff0c;键入js脚本命令回车执行&#xff0c;适用于临时使用脚本逻辑简单的场景&#xff0c;实例如下&#xff1a; // 获取网页元素的文本脚本 var elem document.getElementById("…

2-添加库

本节将学习如何在项目中创建和使用库&#xff0c;还将看到如何使库的使用成为可选的。 本节中使用的示例代码下载见step1-简单开始cmake实践-CSDN博客。 练习1 -创建一个库 要在CMake中添加一个库&#xff0c;使用add_library()命令并指定哪些源文件应该组成该库。 我们可…

接入应用内支付服务,提高商业变现效率

在当今竞争激烈的移动应用市场中&#xff0c;开发者们面临着提升应用商业变现能力的挑战。用户体验的流畅性和支付的安全性至关重要。 HarmonyOS SDK应用内支付服务&#xff08;IAP Kit&#xff09;为开发者提供了一站式的解决方案&#xff0c;简化了应用内支付的接入流程&…

C嘎嘎:类和对象(一)

目录 面向过程和面向对象的初步认识 类的引入 类的定义 类的访问限定符及封装 访问限定符 封装 类的作用域 类的实例化 类对象模型 如何计算类对象大小 结构体内存对齐规则 this指针 this指针的引出 this指针的特性 类的6个默认成员函数 构造函数 概念 特性 …

喜讯丨美格智能通过国际EcoVadis平台认证企业社会责任并荣获承诺奖章,彰显可持续发展实力

作为全球领先的无线通信模组及解决方案提供商&#xff0c;美格智能在社会责任领域再创新高。近日&#xff0c;美格智能凭借在企业社会责任和可持续性采购发展方面的卓越表现&#xff0c;通过国际在线权威评价机构EcoVadis对公司环境、劳工与人权、商业道德、可持续采购等方面审…

根据空格、制表符、回车符等分割字符串re.split

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 根据空格、制表符、 回车符等分割字符串 re.split [太阳]选择题 根据给定的Python代码&#xff0c;哪个选项是正确的&#xff1f; import re pattern r\s print(f"【显示】pattern{…