詳解如何封裝和使用一個(gè)React鑒權(quán)組件
在構(gòu)建復(fù)雜的 Web 應(yīng)用時(shí),經(jīng)常會(huì)遇到需要基于用戶(hù)權(quán)限來(lái)控制元素事件訪問(wèn)性的情況。這不僅涉及到用戶(hù)體驗(yàn)的提升,更關(guān)乎應(yīng)用安全性的加固。JavaScript 和 React 提供了靈活的事件處理機(jī)制,特別是通過(guò)利用事件的捕獲階段來(lái)阻止事件傳播可以實(shí)現(xiàn)精細(xì)的權(quán)限控制。本文將詳細(xì)介紹這一技術(shù)的應(yīng)用,并通過(guò)實(shí)踐案例展示如何封裝和使用一個(gè) React 鑒權(quán)組件。
1. 在事件的捕獲階段阻止事件的傳播
為了更好地理解如何在捕獲階段阻止事件的傳播,讓我們先從一個(gè)完整的 HTML 頁(yè)面示例開(kāi)始:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Event Capture and Authorization</title>
<style>
.container { padding: 20px; background-color: #f0f0f0; }
.button { padding: 10px; background-color: #007bff; color: white; cursor: pointer; }
</style>
</head>
<body>
<div class="container" id="container">
Click Me
<div class="button" id="button">Authorized Action</div>
</div>
<script>
document.getElementById('container').addEventListener('click', function(event) {
alert('Container clicked!');
}, true); // Use capture phase
document.getElementById('button').addEventListener('click', function(event) {
event.stopPropagation(); // Stop event from reaching the container
alert('Button clicked!');
}, false); // Use bubble phase
</script>
</body>
</html>
在這個(gè)示例中,我們有一個(gè)容器和一個(gè)按鈕。當(dāng)按鈕在沒(méi)有授權(quán)的情況下被點(diǎn)擊時(shí),我們通過(guò)在捕獲階段為容器添加的事件監(jiān)聽(tīng)器中調(diào)用 event.stopPropagation() 方法,阻止了事件向上傳播。這樣,即使按鈕被點(diǎn)擊,容器的點(diǎn)擊事件也不會(huì)被觸發(fā),從而實(shí)現(xiàn)了基于權(quán)限的事件控制。
2. 阻止事件傳播的意義
阻止事件在捕獲階段的傳播不僅是一個(gè)技術(shù)行為,它背后的意義更加深遠(yuǎn)。首先,從安全性角度考慮,這可以防止未授權(quán)的用戶(hù)觸發(fā)敏感操作,如刪除數(shù)據(jù)、修改配置等,從而有效地防范安全風(fēng)險(xiǎn)。其次,從用戶(hù)體驗(yàn)角度來(lái)看,合理地控制事件傳播可以避免用戶(hù)誤操作,尤其是在復(fù)雜的交互設(shè)計(jì)中,能夠確保應(yīng)用的操作邏輯更加清晰和穩(wěn)定。最后,這種機(jī)制還提供了一種靈活的事件管理方式,使開(kāi)發(fā)者能夠更精細(xì)地控制應(yīng)用的行為和響應(yīng),增強(qiáng)了應(yīng)用的可維護(hù)性和擴(kuò)展性。
3. 封裝一個(gè)鑒權(quán)組件
在構(gòu)建React前端應(yīng)用時(shí),確保用戶(hù)在執(zhí)行特定操作前已通過(guò)身份驗(yàn)證是常見(jiàn)需求。React 提供了靈活的方式來(lái)處理這種情況,特別是結(jié)合事件捕獲機(jī)制。以下是如何逐步封裝一個(gè)利用事件捕獲機(jī)制進(jìn)行用戶(hù)鑒權(quán)的 React 組件的詳細(xì)解釋。
3.1 使用 useRef 創(chuàng)建引用
const ref = useRef(null);
useRef 是一個(gè) React 鉤子(Hook),它創(chuàng)建了一個(gè)可變的 ref 對(duì)象,并將其賦值為 null。這個(gè) ref 對(duì)象可以被附加到 React 元素上,允許我們直接訪問(wèn) DOM 元素。在我們的鑒權(quán)組件中,這使得我們能夠直接在 DOM 元素上添加和移除事件監(jiān)聽(tīng)器。
3.2 定義事件監(jiān)聽(tīng)器并在捕獲階段注冊(cè)
useEffect(() => {
const handleClickCapture = (e) => {
if(disabled) return;
if(!isUserLogin(window.loginInfo && window.loginInfo.userInfo)) {
e.stopPropagation();
Modal.clear();
Modal.confirm({
bodyClassName: "modal-confirm-body",
content: intl.get("helptext_login_first"),
cancelText: intl.get("text_cancel"),
confirmText: intl.get("text_log_in"),
onConfirm: () => native_LoginAgain.call()
});
}
};
const currentElement = ref.current;
currentElement.addEventListener('click', handleClickCapture, true);
return () => {
currentElement.removeEventListener('click', handleClickCapture, true);
};
}, [disabled]);
在 useEffect 鉤子內(nèi),我們定義了一個(gè) handleClickCapture 函數(shù),該函數(shù)會(huì)在點(diǎn)擊事件發(fā)生時(shí)被調(diào)用。通過(guò)設(shè)置 addEventListener 的第三個(gè)參數(shù)為 true,我們指示瀏覽器在捕獲階段觸發(fā)此監(jiān)聽(tīng)器,而不是冒泡階段。這使我們能夠在事件向下傳播到目標(biāo)元素之前攔截它。
如果組件被標(biāo)記為 disabled,handleClickCapture 函數(shù)會(huì)立即返回,不執(zhí)行任何操作。如果用戶(hù)未登錄(通過(guò) isUserLogin 函數(shù)檢查),函數(shù)會(huì)調(diào)用 e.stopPropagation() 阻止事件進(jìn)一步傳播,然后顯示一個(gè)模態(tài)框(Modal),提示用戶(hù)登錄。
useEffect 的清理函數(shù)確保在組件卸載時(shí)移除事件監(jiān)聽(tīng)器,防止內(nèi)存泄漏。
3.3 組件渲染
return (
<div
ref={ref}
className={className}
style={style}
onClick={(e) => {
if (!disabled && isUserLogin(window.loginInfo && window.loginInfo.userInfo)) {
onClick && onClick(e);
}
}}
>
{children}
</div>
);
在組件的返回語(yǔ)句中,我們將 ref 對(duì)象附加到 div 元素上。這樣,之前定義的事件監(jiān)聽(tīng)器就能夠被正確注冊(cè)到這個(gè) div 上。我們還為這個(gè) div 提供了一個(gè) onClick 事件處理函數(shù)。在這個(gè)函數(shù)內(nèi)部,如果組件未被禁用并且用戶(hù)已登錄,則調(diào)用傳入的 onClick 回調(diào)。這保留了組件原有點(diǎn)擊行為的可能性,但只在用戶(hù)滿(mǎn)足特定條件時(shí)觸發(fā)。
小結(jié)
通過(guò)這種方式,就封裝了一個(gè)可以在事件的捕獲階段根據(jù)用戶(hù)登錄狀態(tài)決定是否允許事件進(jìn)一步傳播的 React 組件。這種模式不僅增強(qiáng)了應(yīng)用的安全性,避免了未授權(quán)的操作,還提高了用戶(hù)體驗(yàn),通過(guò)模態(tài)框提示需要登錄。這種鑒權(quán)組件的封裝展示了 React 以及現(xiàn)代 JavaScript 提供的強(qiáng)大能力,使得開(kāi)發(fā)高質(zhì)量的 Web 應(yīng)用更加高效和靈活。
完整組件代碼
import React, { useEffect, useRef } from "react";
import { isUserLogin } from "../lib/common";
import { Modal } from "antd-mobile";
import intl from "react-intl-universal";
import { native_LoginAgain } from "../lib/nativeUtil";
export default function LoginAuth(props) {
const { disabled, onClick, style, className, children } = props;
const ref = useRef(null); // 使用 useRef 創(chuàng)建一個(gè) ref 對(duì)象
useEffect(() => {
// 定義一個(gè)在捕獲階段執(zhí)行的 handleClick 函數(shù)
const handleClickCapture = (e) => {
if(disabled) return;
if(!isUserLogin(window.loginInfo && window.loginInfo.userInfo)) {
e.stopPropagation(); // 阻止事件在捕獲階段繼續(xù)傳播
Modal.clear();
Modal.confirm({
bodyClassName: "modal-confirm-body",
content: intl.get("helptext_login_first"),
cancelText: intl.get("text_cancel"),
confirmText: intl.get("text_log_in"),
onConfirm: () => native_LoginAgain.call()
});
}
};
// 獲取當(dāng)前 ref 指向的 DOM 元素
const currentElement = ref.current;
// 為該元素添加捕獲階段的事件監(jiān)聽(tīng)器
currentElement.addEventListener('click', handleClickCapture, true);
// 清理函數(shù):組件卸載時(shí)移除事件監(jiān)聽(tīng)器
return () => {
currentElement.removeEventListener('click', handleClickCapture, true);
};
}, [disabled]); // 依賴(lài)項(xiàng)數(shù)組中的元素會(huì)觸發(fā) useEffect 的重新執(zhí)行
return (
<div
ref={ref} // 將 ref 綁定到 div 元素上
className={className}
style={style}
onClick={(e) => {
// 阻止冒泡階段的處理,如果需要
if (!disabled && isUserLogin(window.loginInfo && window.loginInfo.userInfo)) {
onClick && onClick(e);
}
}}
>
{children}
</div>
);
}結(jié)尾
通過(guò)在事件的捕獲階段阻止事件傳播,結(jié)合 React 組件的封裝,不僅能夠有效控制應(yīng)用中的權(quán)限邏輯,還能提升用戶(hù)體驗(yàn)和應(yīng)用安全性。這種技術(shù)的應(yīng)用展示了現(xiàn)代前端開(kāi)發(fā)中,事件處理機(jī)制的強(qiáng)大能力,以及通過(guò)合理設(shè)計(jì)提高應(yīng)用整體質(zhì)量的可能性。在開(kāi)發(fā)實(shí)踐中靈活運(yùn)用這一技術(shù),將有助于構(gòu)建更加穩(wěn)定、安全且用戶(hù)友好的 Web 應(yīng)用。
到此這篇關(guān)于詳解如何封裝和使用一個(gè)React鑒權(quán)組件的文章就介紹到這了,更多相關(guān)React鑒權(quán)組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React通過(guò)conetxt實(shí)現(xiàn)多組件傳值功能
Context 提供了一種在組件之間共享此類(lèi)值的方式,而不必顯式地通過(guò)組件樹(shù)的逐層傳遞 props。本文給大家介紹React通過(guò)conetxt實(shí)現(xiàn)多組件傳值功能,感興趣的朋友一起看看吧2021-10-10
React報(bào)錯(cuò)之組件不能作為JSX組件使用的解決方法
本文主要介紹了React報(bào)錯(cuò)之組件不能作為JSX組件使用的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
React Fiber結(jié)構(gòu)的創(chuàng)建步驟
這篇文章主要介紹了React Fiber結(jié)構(gòu)的創(chuàng)建步驟,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下2021-04-04
react-native聊天室|RN版聊天App仿微信實(shí)例|RN仿微信界面
這篇文章主要介紹了react-native聊天室|RN版聊天App仿微信實(shí)例|RN仿微信界面,需要的朋友可以參考下2019-11-11
React.js入門(mén)實(shí)例教程之創(chuàng)建hello world 的5種方式
React 是近期非常熱門(mén)的一個(gè)前端開(kāi)發(fā)框架。應(yīng)用非常廣泛,接下來(lái)通過(guò)本文給大家介紹React.js入門(mén)實(shí)例教程之創(chuàng)建hello world 的5種方式 ,需要的朋友參考下吧2016-05-05
Express+React+Antd實(shí)現(xiàn)上傳功能(前端和后端)
這篇文章主要介紹了Express+React+Antd實(shí)現(xiàn)上傳功能(前端和后端),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04

