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)=>{// 返回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++;
//   }
// })()

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Oracle中EXIT Statement用于终止循环语句的关键字

Oracle的EXIT Statement是PL/SQL编程语言中用于终止循环语句的关键字。它有两种主要形式&#xff1a;无条件EXIT和条件EXIT WHEN。以下是对Oracle EXIT Statement的详细解释&#xff1a; 1. 无条件EXIT 语法&#xff1a;EXIT; 作用&#xff1a;无条件地终止当前循环。当程序执…

【咨询】企业数字档案馆(室)建设方案-模版范例

导读&#xff1a;本模版来源某国有大型医药行业集团企业数字档案馆&#xff08;室&#xff09;建设方案&#xff08;一期300W、二期250W&#xff09;&#xff0c;本人作为方案的主要参与者&#xff0c;总结其中要点给大家参考。 目录 1、一级提纲总览 2、项目概述 3、总体规…

办公必备——ONLYOFFICE8.1版本桌面编辑器

一、介绍ONLYOFFICE ONLYOFFICE是一款免费的开源办公软件&#xff0c;它可以让你创建、编辑和分享文档、表格和演示文稿。就像微软的Office一样&#xff0c;但它是完全免费的&#xff0c;而且可以在多种设备上使用&#xff0c;包括电脑和手机。它还支持多人同时在线编辑文档&am…

SpringCloud 负载均衡

目录 一、负载均衡 1、问题 2、什么是负载均衡 服务端负载均衡 客户端负载均衡 二、Spring Cloud LoadBalance 1、使用 Spring Cloud LoadBalance 2、负载均衡策略 3、LoadBalancer 原理 一、负载均衡 1、问题 我们来看一下前面写的代码&#xff1a; List<Serv…

抖音矩阵云剪系统saas源码 短视频矩阵获客管理系统

2024抖音矩阵云混剪系统是一款专业的短视频营销管理工具。该系统支持多平台多账号的集中式管理&#xff0c;并实现一键式作品发布功能。它配备了智能标题生成和关键词优化工具&#xff0c;以及排名查询机制&#xff0c;帮助用户提升内容在平台上更好的矩阵管理. 智能剪辑 托管发…

java中 使用数组实现需求小案例

Date: 2024.04.08 18:32:57 author: lijianzhan 需求实现&#xff1a; 设计一个java类&#xff0c;java方法&#xff0c;根据用户手动输入的绩点&#xff0c;从而获取到绩点最高的成绩。 实现业务逻辑的代码块 import java.util.Scanner;public class PointDemo {/*** 需求&…

Python 如何实现数据驱动的接口自动化测试

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 大家在接口测试的过程中&#xff0c;很多时候会用到对CSV的读取操作&#xff0c;本文主要说明Pyt…

【Java]认识泛型

包装类 在Java中&#xff0c;由于基本类型不是继承自Object&#xff0c;为了在泛型代码中可以支持基本类型&#xff0c;Java给每个基本类型都对应了一个包装类型。 除了 Integer 和 Character&#xff0c; 其余基本类型的包装类都是首字母大写。 泛型 泛型是在JDK1.5引入的…

spring boot 3.x版本中集成spring security 6.x版本进行实现动态权限控制解决方案

一、背景 最近在进行项目从jdk8和spring boot 2.7.x版本技术架构向jdk17和spring boot 3.3.x版本的代码迁移&#xff0c;在迁移过程中&#xff0c;发现spring boot 3.3.x版本依赖的spring security版本已经升级6.x版本了&#xff0c;语法上和spring security 5.x版本有很多地方…

AntV X6 图编辑引擎速通

前言&#xff1a;参考 [AntV X6 官网](https://x6.antv.antgroup.com/) 一、简介 X6 可以快速搭建 DAG 图、ER 图、流程图、血缘图等应用。 二、快速上手 1. 安装 npm install antv/x6 --save# oryarn add antv/x6# orpnpm add antv/x6 2. 使用 2.1 初始画布 在页面中创…

【Linux进阶】文件系统3——目录树,挂载

前言 在Windows 系统重新安装之前&#xff0c;你可能会事先考虑&#xff0c;到底系统盘C盘要有多大容量&#xff1f;而数据盘D盘又要给多大容量等&#xff0c;然后实际安装的时候&#xff0c;你会发现其实C盘之前会有个100MB的分区被独立出来&#xff0c;所以实际上你就会有三个…

Java进阶----继承

继承 一.继承概述 继承是可以通过定义新的类&#xff0c;在已有类的基础上扩展属性和功能的一种技术. 案例&#xff1a;优化 猫、狗JavaBean类的设计 狗类&#xff1a;Dog 属性&#xff1a;名字 name&#xff0c;年龄 age 方法&#xff1a;看家 watchHome()&#xff0c;Gett…

QT5.12.9 通过MinGW64 / MinGW32 cmake编译Opencv4.5.1

一、安装前准备&#xff1a; 1.安装QT,QT5.12.9官方下载链接&#xff1a;https://download.qt.io/archive/qt/5.12/5.12.9/ QT安装教程&#xff1a;https://blog.csdn.net/Mark_md/article/details/108614209 如果电脑是64位就编译器选择MinGW64&#xff0c;32位就选择MinGW…

C#描述-计算机视觉OpenCV(5):直方图算法

C#描述-计算机视觉OpenCV&#xff08;5&#xff09;&#xff1a;直方图算法 前文链接图像直方图灰度直方图的计算灰度直方图的绘制BGR三通道的直方图直方图的均衡化算法相似图像检测 前文链接 文中没提到的东西&#xff0c;很可能都在前文描述过 C#描述-计算机视觉OpenCV&…

【C++深度探索】继承机制详解(二)

hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1…

深入解析:抖音视频标题的Python爬虫提取方法

引言 随着短视频的兴起&#xff0c;抖音已经成为全球最受欢迎的社交媒体平台之一。对于数据分析师、市场研究人员以及内容创作者来说&#xff0c;能够从抖音上抓取数据是一项宝贵的技能。本文将深入解析如何使用Python编写爬虫程序来提取抖音视频的标题。 爬虫基础 在开始编…

K8S 上部署大数据相关组件

文章目录 一、前言二、Redis 一、前言 Artifact Hub 是一个专注于云原生应用的集中式搜索和发布平台。它旨在简化开发者在 CNCF&#xff08;Cloud Native Computing Foundation&#xff09;项目中寻找、安装和分享包与配置的过程。用户可以通过这个平台方便地发现、安装各类云原…

为什么需要重写equals和如何重写equals

首先先看Java中的 &#xff0c;比较的两个对象的地址值。 如果是基本数据类型&#xff0c;那么就是比较的是值。 如果是引用数据类型&#xff0c;比较的就是地址. object类中的equals方法也是用的&#xff1b; 所以要比较两个对象的大小&#xff0c;去调用默认的equals方法…

Apache Spark分布式计算框架架构介绍

目录 一、概述 二、Apache Spark架构组件栈 2.1 概述 2.2 架构图 2.3 架构分层组件说明 2.3.1 支持数据源 2.3.2 调度运行模式 2.3.3 Spark Core核心 2.3.3.1 基础设施 2.3.3.2 存储系统 2.3.3.3 调度系统 2.3.3.4 计算引擎 2.3.4 生态组件 2.3.4.1 Spark SQL 2.…

关系型数据库MySQL和时序数据库的区别?

时序数据库和关系型数据库是两种不同类型的数据库系统&#xff0c;它们在设计理念、存储结构、性能优化等方面有显著差异&#xff0c;以适应不同的应用场景和需求。具体对比如下&#xff1a; 数据存储结构 时序数据库&#xff1a;使用列式存储&#xff0c;每条记录通常包含时间…