Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Analyse der Kernhistorienbibliothek in React Router

Detaillierte Analyse der Kernhistorienbibliothek in React Router

不言
不言Original
2018-08-14 11:01:563043Durchsuche

Dieser Artikel stellt Ihnen eine detaillierte Analyse der Kernhistorienbibliothek in React Router vor. Ich hoffe, dass er für Freunde hilfreich ist.

Vorwort

React Router ist fast die einzige Wahl für die Routing-Verwaltung, um etwas komplexere Anwendungen zu entwickeln. Obwohl React Router vier große Versionsaktualisierungen durchlaufen hat und seine Funktionen immer umfangreicher geworden sind, hat sich seine Kernabhängigkeit von der Verlaufsbibliothek nicht geändert, egal wie er sich ändert. Werfen wir einen Blick darauf, welche Funktionen diese Bibliothek mit 4k+ Sternen auf Github bietet.

HTML5-Verlaufsobjekt

Apropos Geschichtsbibliothek: Denken Sie, dass Ihnen dieses Wort ein wenig bekannt vorkommt? Ja, der HTML5-Spezifikation wurde auch ein neues Verlaufsobjekt mit demselben Namen hinzugefügt. Werfen wir einen Blick darauf, welche Probleme mit diesem Verlaufsobjekt gelöst werden.

In der Zeit, als jQuery das Front-End dominierte, war das Anfordern von Seitenaktualisierungen über Ajax zu dieser Zeit eine sehr beliebte Methode zur Seitenverarbeitung. Zu dieser Zeit entwickelte sich der Prototyp von SPA. Um Änderungen an der Seite zu kennzeichnen, sodass nach dem Aktualisieren weiterhin die richtigen Seitenelemente angezeigt werden können, wird in der Regel der Hashwert der URL geändert, um die Seite eindeutig zu lokalisieren. Dies bringt jedoch ein weiteres Problem mit sich: Benutzer können die Seiten nicht vorwärts/rückwärts wechseln.

Um dieses Problem zu lösen, wurde das History-Objekt ins Leben gerufen. Wenn sich die URL oder der Hash der Seite ändert, überträgt der Browser automatisch die neue URL in das Verlaufsobjekt. Im Verlaufsobjekt wird ein Statusarray verwaltet, um Änderungen in der URL aufzuzeichnen. Wenn der Browser Vorwärts-/Rückwärtsvorgänge ausführt, ruft er tatsächlich die entsprechende Methode des Verlaufsobjekts (forward/back) auf, um den entsprechenden Status zum Seitenwechsel abzurufen.

Zusätzlich zur Bedienung der URL bietet das Verlaufsobjekt auch zwei Methoden, mit denen der interne Status aktualisiert werden kann, ohne die URL zu bedienen, nämlich pushState und replaceState. Sie können auch zusätzliche Daten im Status speichern und diese dann über onpopstate im Ereignis event.state abrufen. Wenn Sie ein tieferes Verständnis des Verlaufsobjekts wünschen, können Sie hier und hier nachschlagen.

Die Beziehung zwischen der Verlaufsbibliothek und dem HTML5-Verlaufsobjekt

Lassen Sie uns zurückgehen und einen Blick auf die Verlaufsbibliothek werfen. Es führt im Wesentlichen die folgenden vier Dinge aus:

  1. Lernen aus dem Konzept des HTML5-Verlaufsobjekts und Erweitern einiger darauf basierender Funktionen

  2. Bietet 3 Arten von Verlauf: BrowserHistory, HashHistory, MemoryHistory und verwaltet eine einheitliche API

  3. Unterstützt die Publish/Subscribe-Funktion. Wenn sich der Verlauf ändert, kann die Abonnementfunktion automatisch ausgelöst werden

  4. Bietet praktische Funktionen wie Sprungabfangen, Sprungbestätigung und Basisname

Vergleichen Sie einige Ähnlichkeiten und Unterschiede zwischen den beiden APIs. Das Folgende ist die Verlaufsbibliothek:

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变更事件
  };

Das Folgende ist das HTML5-Verlaufsobjekt:

const history = {
    length,         // 属性,history中记录的state的数量
    state,          // 属性,pushState和replaceState时传入的对象
    back,           // 方法,后退
    forward,        // 方法,前进
    go,             // 方法,前进或后退n个记录
    pushState,      // 方法,导航到新的路由,并记录在history中
    replaceState    // 方法,替换掉当前记录在history中的路由信息
}

// 订阅history变更事件
window.onpopstate = function (event) {
    ...
}

Aus dem Vergleich ist ersichtlich, dass die Beziehung zwischen den beiden sehr eng ist Man kann sagen, dass es sich um das Verlaufsobjekt handelt. Eine Obermenge von , bei der es sich um ein leistungsfähigeres Verlaufsobjekt handelt.

createHashHistory-Quellcode-Analyse

Im Folgenden nehmen wir einen der drei Verlaufstypen, hashHistory, als Beispiel, um den Verlaufsquellcode zu analysieren und zu sehen, was er bewirkt. Schauen wir uns zunächst an, wie es mit Hash-Änderungen umgeht.

// 构造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);
    };
    ...
}

Das Obige ist die Logik für den Umgang mit passiven Hash-Änderungen. In einem Satz kann sie wie folgt zusammengefasst werden: Abonnieren Sie das Hash-Änderungsereignis, stellen Sie fest, ob die Änderung wirklich erforderlich ist, und aktualisieren Sie Ihre eigenen Attribute, wenn a Wenn eine Änderung erforderlich ist, benachrichtigen Sie den Abonnenten. Wenn keine Änderung erforderlich ist, kehren Sie zum vorherigen Status zurück.

Schauen wir uns an, was der TransitionManager tut. Konzentrieren Sie sich auf den Inhalt im Zusammenhang mit dem Veröffentlichen/Abonnieren und ignorieren Sie den Inhalt im Zusammenhang mit dem Benutzerbestätigungssprung.

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));
    };
    ...
}

Der Code hier ist auf den ersten Blick klar. Er dient dazu, eine Abonnentenliste zu verwalten und die relevanten Funktionen zu benachrichtigen, wenn sich der Hash ändert.

Das Obige ist der Inhalt, der sich auf die passive Aktualisierung bezieht, wenn sich der Hash ändert. Am Beispiel von push ist der Code ähnlich. 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);
Wenn der Browser Vorwärts- und Rückwärtsoperationen ausführt, wird die Verlaufsbibliothek tatsächlich durch Betreiben des HTML5-Verlaufsobjekts implementiert.

const globalHistory = window.history;

const go = n => {
    ...
    globalHistory.go(n);
};

const goBack = () => go(-1);

const goForward = () => go(1);
Wenn

aufgerufen wird, ändert sich der Hash, was das Hashchange-Ereignis auslöst, und dann benachrichtigt die Verlaufsbibliothek die relevanten Abonnenten über die Änderung. window.history.go

Zusammenfassung

Dieser Artikel bietet eine ausführlichere Einführung in die Verlaufsbibliothek, auf der der React Router-Kern basiert. Ausgehend vom neuen Verlaufsobjekt in HTML5 vergleichen wir seine untrennbare Beziehung mit der Verlaufsbibliothek und verwenden hashHistory als Beispiel, um die Implementierungsdetails seines Codes im Detail zu analysieren.

Lassen Sie uns zum Schluss einen Blick darauf werfen, was die Verlaufsbibliothek geleistet hat:

  1. Lernen Sie vom Konzept des HTML5-Verlaufsobjekts und erweitern Sie einige darauf basierende Funktionen

  2. Bietet 3 Arten von Verlauf: BrowserHistory, HashHistory, MemoryHistory und verwaltet eine einheitliche API

  3. Unterstützt die Publish/Subscribe-Funktion, wenn sich der Verlauf zeitlich ändert, die Funktion, die kann das Abonnement automatisch auslösen

  4. Bietet praktische Funktionen wie Sprungabfang, Sprungbestätigung und Basisname

Obwohl die Verlaufsbibliothek die Kernabhängigkeit von React Router ist , aber es besteht keine Abhängigkeit von React selbst. Wenn Ihr Projekt über ein Verlaufsmanipulationsszenario verfügt, können Sie es auch in das Projekt einführen.

Verwandte Empfehlungen:

Wie man h5 verwendet, um reagierende Drag-and-Drop-Sortierkomponenten (mit Code) zu implementieren

Wie HTML5 das Kollapsproblem von löst margin-top (Code beigefügt)

Was sind die Tags und allgemeinen Regeln in HTML5? Einführung in HTML5-Tags und -Regeln


Das obige ist der detaillierte Inhalt vonDetaillierte Analyse der Kernhistorienbibliothek in React Router. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn