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

news2024/9/27 21:22:14

 本文为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)=>{// 返回promise
          dom.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.coloradmin.cn/o/1909522.html

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

相关文章

activemq-CVE-2022-41678

Apache ActiveMQ Jolokia 后台远程代码执行漏洞 Apache ActiveMQ在5.16.5&#xff0c;5.17.3版本及以前&#xff0c;后台Jolokia存在一处任意文件写入导致的远程代码执行漏洞。 启动环境 admin/admin 方法一&#xff1a;利用poc 这个方法受到ActiveMQ版本的限制&#xff0c;因…

矢量数据库:LLMs外挂知识库

矢量数据库为管理高维数据提供了专门的解决方案&#xff0c;这对人工智能的上下文决策至关重要。但它们究竟是如何做到的呢&#xff1f; 介绍 信息有多种形式。有些信息是非结构化的&#xff0c;例如文本文档、图片和音频。有些则是结构化的&#xff0c;例如应用程序日志、表格…

【可视化大屏系列】Echarts之柱图绘制

本文为个人近期学习总结&#xff0c;若有错误之处&#xff0c;欢迎指出&#xff01; Echarts之柱图绘制 前言需求实现效果大概思路具体实现实现思路具体代码1.父组件写法2.子组件写法 附加1.同坐标系下&#xff0c;并排柱图绘制2.柱图下钻功能实现 前言 在前文页面布局、DataV…

HW期间——应急响应

01HW中应急响应的流程 001应急响应所处位置&#xff08;应急处置组&#xff09; 监控研判组发现的一些安全时间提供给应急处置组&#xff0c;应急处置组通过上机取证把线索给到溯源反制组。但是溯源反制组可能已经没有了&#xff0c;有些单位有&#xff0c;有些单位取消了。有…

标准扩散模型(standard diffusion)和潜在(latent diffusion)扩散模型的关键区别、对潜在扩散模型的认识

标准扩散模型(standard diffusion)和潜在(latent diffusion)扩散模型的关键区别、对潜在扩散模型的认识 1.两者的关键区别 潜在扩散模型通过在低维潜在空间的扩散过程&#xff0c;可以减少内存和计算的复杂性。而standard diffusion是在像素级别的空间(actual pixel space)进…

CSS上下悬浮特效

要实现一个上下悬浮的特效&#xff0c;可以使用CSS的keyframes规则和动画属性。以下是一个简单的示例&#xff1a; 代码示例 /* 定义一个名为floating的动画 */ keyframes floating {0% {transform: translateY(0); /* 初始位置 */}50% {transform: translateY(-4px); /* 向上…

吴恩达机器学习笔记2.1 - 什么是机器学习

吴恩达机器学习笔记2.1 - 什么是机器学习 最早的机器学习 1959年&#xff0c;亚瑟塞缪尔(Arthur Samuel)将机器学习定义为“Field of study that gives computers the ability to learn without being explicitly programmed”&#xff08;无需编程即可学习的研究领域&#xf…

ABAP BAPI_INCOMINGINVOICE_CREATE dump

在执行BAPI_INCOMINGINVOICE_CREATE 之后&#xff0c;正常生成了发票号&#xff0c;但是系统会dump 数据会回滚 dump如下 查阅后得知相关note:1894901 原因是在填写税行的时候&#xff0c;输入了多行&#xff0c;将数据合并为一行后即可 代码如下&#xff1a; ls_headerdat…

openlayers更改点坐标

我现在的需求是无人机点位根据ws传输的经纬度改变位置&#xff0c;在网上查了很多资料&#xff0c;终于是做出来了&#xff0c;如果有问题请指出。 效果图&#xff0c;无人机可以来回移动 这里是核心代码 // 添加飞机点位图层let vectorLayerpointfunction DronepointLayer()…

vscode设置左侧窗口字体大小

vscode设置左侧窗口字体大小 打开设置 在搜索框输入Zoom 修改这个值即可放大相关字体

从数字化营销与运营视角:看流量效果的数据分析

基于数据打通的“全链路”营销是当下的“时髦”&#xff0c;应用它的前提是什么&#xff1f;深度营销和运营的关键数据如何获得&#xff1f;如何利用数据进行更精准的营销投放&#xff1f;如何利用数据优化投放的效果&#xff1f;如何促进消费者的转化&#xff0c;以及激活留存…

【js面试题】深入理解尾递归及其在JavaScript中的应用

面试题&#xff1a;举例说明尾递归的理解&#xff0c;以及应用场景 引言&#xff1a; 在编程中&#xff0c;递归是一种常见的解决问题的方法&#xff0c;它允许函数调用自身来解决问题。然而&#xff0c;递归如果不当使用&#xff0c;可能会导致栈溢出错误&#xff0c;特别是在…

无损音频格式 FLAC 转 MP3 音频图文教程

音频文件的格式多样&#xff0c;每种格式都有其独特的特点与适用场景。FLAC&#xff08;Free Lossless Audio Codec&#xff09;&#xff0c;作为一种无损音频压缩格式&#xff0c;因其能够完美保留原始音频数据的每一个细节而备受音频发烧友和专业人士的青睐。 然而&#xff0…

代码随想录打卡第十八天

代码随想录–二叉树部分 day 17 休息日 day 18 二叉树第五天 文章目录 代码随想录--二叉树部分一、力扣654--最大二叉树二、力扣617--合并二叉树三、力扣700--二乘树中的搜素四、力扣98--验证二叉搜索树 一、力扣654–最大二叉树 代码随想录题目链接&#xff1a;代码随想录 给…

双系统ubuntu20.04扩容

windows端 打开磁盘管理器&#xff0c;选择需要的盘点击压缩卷 点击未分配的盘&#xff0c;新建简单卷&#xff0c;一致点击下一步即可&#xff0c;记住分配的大小容量 ubuntu端 lsblk 查看所有的磁盘&#xff0c;可以看到新增为nvme0n1p4、nvme1n1p2 win分配的格式为NTFS&a…

Idea-单个窗口导入并开启多个module项目

前言 大家是否有过这样的困扰&#xff0c;我们每次打开一个项目就需要单开一个idea窗口&#xff0c;项目少时了还好&#xff0c;一旦涉及多个项目间服务调用&#xff0c;特别是再包括网关、注册中心、前端web服务&#xff0c;需要开启的窗口就会是一大批&#xff0c;每次切换的…

antd a-select下拉框样式修改 vue3 亲测有效

记录一下遇到的问题 1.遇到问题&#xff1a; 使用到Vue3 Ant Design of Vue 3.2.20&#xff0c;但因为项目需求样式&#xff0c;各种查找资料都未能解决; 2.解决问题&#xff1a; ①我们审查元素可以看到&#xff0c;下拉框是在body中的; ①在a-select 元素上添加dropdownCla…

在Linux下使用Docker部署chirpstack

目录 一、前言 二、chirpstack 1、chirpstack是什么 2、chirpstack组件 3、为什么选择Docker部署 三、Linux下部署过程 四、web界面部署过程 一、前言 本篇文章我是在Linux下使用 Docker 进行部署chirpstack&#xff0c;chirpstack采用的是v4 版本&#xff0c;v4 版本 与…

AMEYA360荣登2024电子元器件分销商30强!

2024年7月4日&#xff0c;“2024(第二届)电子产业供应链生态大会”在东莞顺利召开。 本次大会由中国物流与采购联合会和东莞市人民政府联合主办&#xff0c;由中国物流与采购联合会电子产业供应链分会承办&#xff0c;该会议以“智链端生态 互链芯未来”为主题&#xff0c;旨在…

你最近想通了什么事情?这10条职场经验帮助你活得更通透

1别总当老好人 记得刚步入职场那会儿&#xff0c;我简直是“老好人”的代名词。 无论是同事的额外任务&#xff0c;还是朋友的小忙&#xff0c;我总是二话不说就接下来&#xff0c;结果自己累得半死&#xff0c;换来的却是别人的理所当然和偶尔的忽视。 直到有一次&#xff…