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.pswp.cn/web/42406.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42406.shtml
英文地址,請注明出處:http://en.pswp.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{…