Cet article vous présente une analyse détaillée de la bibliothèque d'historique de base de React Router. Elle a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Utiliser React pour développer des applications légèrement plus complexes. React Router est presque le seul choix pour la gestion du routage. Bien que React Router ait subi quatre mises à jour de version majeures et que ses fonctions soient devenues de plus en plus abondantes, quelle que soit la manière dont il évolue, sa dépendance fondamentale à l'égard de la bibliothèque d'historique n'a pas changé. Jetons un coup d'œil aux fonctions fournies par cette bibliothèque avec plus de 4 000 étoiles sur github.
En parlant de bibliothèque d'histoire, pensez-vous que ce mot vous est un peu familier ? Oui, un nouvel objet historique portant le même nom a également été ajouté à la spécification HTML5. Jetons un coup d'œil aux problèmes que cet objet d'historique est utilisé pour résoudre.
À l'époque où jQuery dominait le front-end, la mise à jour de la page sans actualisation via une requête ajax était une méthode de traitement de page très populaire à cette époque. Le prototype de SPA évoluait à cette époque. Afin de marquer les modifications apportées à la page afin que les éléments corrects de la page puissent toujours être affichés après l'actualisation, la valeur de hachage de l'URL est généralement modifiée pour localiser la page de manière unique. Mais cela soulève un autre problème : les utilisateurs ne peuvent pas utiliser avant/arrière pour changer de page.
Afin de résoudre ce problème, l'objet historique a vu le jour. Lorsque l'URL ou le hachage de la page change, le navigateur insère automatiquement la nouvelle URL dans l'objet historique. Un tableau d'état sera conservé à l'intérieur de l'objet historique pour enregistrer les modifications apportées à l'URL. Lorsque le navigateur effectue des opérations avant/arrière, il appelle en fait la méthode correspondante de l'objet historique (forward
/back
) pour récupérer l'état correspondant pour changer de page.
En plus d'exploiter l'URL, l'objet historique fournit également deux méthodes qui peuvent mettre à jour l'état interne sans utiliser l'URL, à savoir pushState
et replaceState
. Vous pouvez également stocker des données supplémentaires dans l'état, puis les récupérer via onpopstate
dans l'événement event.state
. Si vous souhaitez une compréhension plus approfondie de l'objet historique, vous pouvez vous référer à ici et ici.
Retournons et regardons la bibliothèque d'historique. Il fait essentiellement les 4 choses suivantes :
Apprendre du concept d'objet historique HTML5 et étendre certaines fonctions basées sur celui-ci
Fournit 3 types d'historique : browserHistory, hashHistory, memoryHistory et maintient une API unifiée
Prend en charge la fonction de publication/abonnement lorsque l'historique change, la fonction d'abonnement peut être automatiquement déclenchée
const history = { length, // 属性,history中记录的state的数量 action, // 属性,当前导航的action类型 location, // 属性,location对象,封装了pathname、search和hash等属性 push, // 方法,导航到新的路由,并记录在history中 replace, // 方法,替换掉当前记录在history中的路由信息 go, // 方法,前进或后退n个记录 goBack, // 方法,后退 goForward, // 方法,前进 canGo, // 方法,是否能前进或后退n个记录 block, // 方法,跳转前让用户确定是否要跳转 listen // 方法,订阅history变更事件 };
const history = { length, // 属性,history中记录的state的数量 state, // 属性,pushState和replaceState时传入的对象 back, // 方法,后退 forward, // 方法,前进 go, // 方法,前进或后退n个记录 pushState, // 方法,导航到新的路由,并记录在history中 replaceState // 方法,替换掉当前记录在history中的路由信息 } // 订阅history变更事件 window.onpopstate = function (event) { ... }
// 构造hashHistory对象 const createHashHistory = (props = {}) => { ... const globalHistory = window.history; // 引用HTML5 history对象 ... // transitionManager负责控制是否进行跳转,以及跳转后要通知到的订阅者,后面会详细讨论 const transitionManager = createTransitionManager(); ... // 注册history变更回调的订阅者 const listen = listener => { const unlisten = transitionManager.appendListener(listener); checkDOMListeners(1); return () => { checkDOMListeners(-1); unlisten(); }; }; // 监听hashchange事件 const checkDOMListeners = delta => { listenerCount += delta; if (listenerCount === 1) { window.addEventListener(HashChangeEvent, handleHashChange); } else if (listenerCount === 0) { window.removeEventListener(HashChangeEvent, handleHashChange); } }; // hashchange事件回调 const handleHashChange = () => { ... // 构造内部使用的location对象,包含pathname、search和hash等属性 const location = getDOMLocation(); ... handlePop(location); }; // 处理hash变更逻辑 const handlePop = location => { ... const action = "POP"; // 给用户展示确认跳转的信息(如果有的话),确认后通知订阅者。如果用户取消跳转,则回退到之前状态 transitionManager.confirmTransitionTo(location, action, getUserConfirmation, ok => { if (ok) { setState({action, location}); // 确认后通知订阅者 } else { revertPop(location); // 取消则回退到之前状态 } }); }; // 更新action,location和length属性,并通知订阅者 const setState = nextState => { Object.assign(history, nextState); history.length = globalHistory.length; transitionManager.notifyListeners(history.location, history.action); }; ... }
const createTransitionManager = () => { ... // 内部维护的订阅者列表 let listeners = []; // 注册订阅者 const appendListener = fn => { let isActive = true; const listener = (...args) => { if (isActive) fn(...args); }; listeners.push(listener); return () => { isActive = false; listeners = listeners.filter(item => item !== listener); }; }; //通知订阅者 const notifyListeners = (...args) => { listeners.forEach(listener => listener(...args)); }; ... }
comme exemple, push
est similaire. replace
const push = (path, state) => { ... const action = "PUSH"; const location = createLocation(path, undefined, undefined, history.location); transitionManager.confirmTransitionTo(location, action, getUserConfirmation, ok => { if (!ok) // 如果取消,则不跳转 return; ... pushHashPath(encodedPath); // 用新的hash替换到url当中 ... setState({action, location}); // 更新action,location和length属性,并通知订阅者 }); }; // 用新的hash替换到url当中 const pushHashPath = path => (window.location.hash = path);
const globalHistory = window.history; const go = n => { ... globalHistory.go(n); }; const goBack = () => go(-1); const goForward = () => go(1);
est appelé, le hachage changera, déclenchant l'événement hashchange, puis la bibliothèque d'historique informera les abonnés concernés du changement. window.history.go
Recommandations associées :
Comment utiliser h5 pour implémenter des composants de tri par glisser-déposer (avec code)
Comment HTML5 résout le problème d'effondrement de margin-top (Code ci-joint)
Quelles sont les balises et les règles communes en HTML5 ? Introduction aux balises et règles html5
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!