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++;
//   }
// })()

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3中引入了Proxy作为响应式系统的核心,它可以用于代理对象并拦截其属性的访问。通过使用Proxy,我们可以更加灵活地对数据进行监听和响应。 在Vue 3中,使用Proxy代理的步骤如下: 1. 创建一个普通的JavaScript对象作为数据源。 2. 使用`new Proxy(target, handler)`创建一个代理对象,其中`target`是要代理的对象,`handler`是一个包含拦截器方法的对象。 3. 在`handler`对象中定义拦截器方法,例如`get`、`set`、`deleteProperty`等。这些方法会在对代理对象进行相应操作时被调用。 4. 将代理对象作为Vue实例的数据源。 下面是一个简单的示例代码,演示了如何使用Proxy代理对象: ```javascript // 创建一个普通的JavaScript对象作为数据源 const data = { name: 'John', age: 25 }; // 使用Proxy创建代理对象 const proxy = new Proxy(data, { get(target, key) { console.log(`访问了属性 ${key}`); return target[key]; }, set(target, key, value) { console.log(`设置了属性 ${key} 的值为 ${value}`); target[key] = value; } }); // 将代理对象作为Vue实例的数据源 const app = Vue.createApp({ data() { return { person: proxy }; } }); // 在Vue模板中使用代理对象的属性 app.mount('#app'); ``` 在上述示例中,我们创建了一个普通的JavaScript对象`data`作为数据源,并使用Proxy创建了代理对象`proxy`。在代理对象的`get`和`set`方法中,我们分别打印了访问和设置属性的信息,并对原始对象进行了相应的操作。最后,将代理对象作为Vue实例的数据源,并在Vue模板中使用代理对象的属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值