Heim > Web-Frontend > js-Tutorial > Hauptteil

Detaillierte Erläuterung der gesamten Architekturanalyse und Implementierung von jquery. examples_jquery

WBOY
Freigeben: 2016-05-16 16:31:57
Original
1273 Leute haben es durchsucht

Das gesamte jQuery-Framework ist sehr komplex und nicht leicht zu verstehen. Ich habe dieses umfangreiche und leistungsstarke Framework in den letzten Tagen studiert. Die Gesamtarchitektur von jQuery kann unterteilt werden in: Einstiegsmodul, unteres Modul und Funktionsmodul. Hier nehmen wir jquery-1.7.1 als Beispiel für die Analyse.

Die Gesamtarchitektur von jquery

Code kopieren Der Code lautet wie folgt:

16 (Funktion( Fenster, undefiniert) {
                    // jQuery-Objekt erstellen
22 var jQuery = (function() {
25 var jQuery = function(selector, context) {
27                     return new jQuery.fn.init( selector, context, rootjQuery);
28 },
// Eine Reihe lokaler Variablendeklarationen
97 jQuery.fn = jQuery.prototype = {
98          Konstruktor: jQuery,
99 init: function(selector, context, rootjQuery) { ... },
// Eine Reihe von Prototypeigenschaften und -methoden
319 };
322          jQuery.fn.init.prototype = jQuery.fn;
324        jQuery.extend = jQuery.fn.extend = function() { ... };
388 jQuery.extend({
// Eine Reihe statischer Eigenschaften und Methoden
892 });
955        jQuery zurückgeben;
957 })();
//Den Code anderer Module weglassen...
9246  window.jQuery = window.$ = jQuery;
9266 })( Fenster );

Bei der Analyse des obigen Codes haben wir festgestellt, dass JQuery die Schreibmethode der Selbstausführung anonymer Funktionen übernimmt. Der Vorteil davon besteht darin, dass das Problem der Namensraum- und Variablenverschmutzung wirksam verhindert werden kann. Die Abkürzung des obigen Codes lautet:

Code kopieren Der Code lautet wie folgt:

(Funktion(Fenster, undefiniert) {
var jQuery = function() {}
// ...
​ window.jQuery = window.$ = jQuery;
})(Fenster);

Parameterfenster

Die anonyme Funktion übergibt zwei Parameter, einer ist Fenster und der andere ist undefiniert. Wir wissen, dass Variablen in js Bereichsketten haben. Die beiden übergebenen Variablen werden zu lokalen Variablen der anonymen Funktion und der Zugriff erfolgt schneller. Durch die Übergabe des Fensterobjekts kann das Fensterobjekt als lokale Variable verwendet werden. Beim Zugriff auf das Fensterobjekt in jquery ist es nicht erforderlich, die Bereichskette an die Spitze zurückzugeben -Ebenenbereich, sodass auf das Fensterobjekt schneller zugegriffen werden kann.

Parameter undefiniert

Wenn js nach einer Variablen sucht, sucht die js-Engine zunächst im Bereich der Funktion selbst nach der Variablen. Wenn sie nicht vorhanden ist, wird die Suche nach oben fortgesetzt . Wenn es nicht gefunden werden kann, wird undefiniert zurückgegeben. undefiniert ist eine Eigenschaft des Fensterobjekts. Durch die Übergabe des undefinierten Parameters ohne Zuweisung eines Werts kann die Gültigkeitskette bei der Suche nach undefiniert verkürzt werden. Stellen Sie im Rahmen einer selbstaufrufenden anonymen Funktion sicher, dass undefiniert wirklich undefiniert ist. Denn undefiniert kann überschrieben und mit einem neuen Wert versehen werden.

Was ist jquery.fn?

Code kopieren Der Code lautet wie folgt:

jQuery.fn = jQuery.prototype = {
               Konstruktor: jQuery,
                init: function(selector, context, rootjQuery) { ... },
// Eine Reihe von Prototypeigenschaften und -methoden
        };

Durch die Analyse des obigen Codes haben wir festgestellt, dass jQuery.fn jQuery.prototype ist. Der Vorteil dieser Schreibweise besteht darin, dass es kürzer ist. Später haben wir gesehen, dass jquery der Einfachheit halber einfach ein $-Symbol anstelle von jquery verwendet hat. Daher verwenden wir oft $(), wenn wir das jquery-Framework verwenden,

Konstruktor jQuery()

Bildbeschreibung

jQuery-Objekte werden nicht durch neue jQuery erstellt, sondern durch neue jQuery.fn.init:

Code kopieren Der Code lautet wie folgt:

var jQuery = function(selector, context) {

new jQuery.fn.init( selector, context, rootjQuery ) zurückgeben;

}

Hier wird eine jQuery-Variable definiert, deren Wert der jQuery-Konstruktor ist, der zurückgegeben und der jQuery-Variablen in Zeile 955 (oberster Code) zugewiesen wird

jQuery.fn.init

jQuery.fn (Zeile 97 oben) ist das Prototypobjekt der Konstruktorfunktion jQuery() und jQuery.fn.init() ist die jQuery-Prototypmethode, die auch als Konstruktor bezeichnet werden kann. Verantwortlich für das Parsen der Parametertypen Selektor und Kontext sowie für die Durchführung entsprechender Suchvorgänge.

Parameterkontext: Sie können ihn nicht übergeben, oder Sie können ihn in einem jQuery-Objekt, einem DOM-Element oder einem der gewöhnlichen js-Objekte übergeben
Parameter rootjQuery: jQuery-Objekt, das das Dokumentobjekt enthält und für Situationen wie einen document.getElementById()-Fehler verwendet wird.

Code kopieren Der Code lautet wie folgt:

jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
jQuery(selector [,context])

Standardmäßig beginnt die Suche nach übereinstimmenden Elementen beim Stammelement-Dokumentobjekt, d. h. der Suchbereich ist der gesamte Dokumentbaum, Sie können jedoch auch den zweiten Parameter context übergeben, um den Suchbereich einzuschränken. Zum Beispiel:

Code kopieren Der Code lautet wie folgt:

$('div.foo').click(function () {
                 $('span',this).addClass('bar');//Beschränken Sie den Suchbereich, d. h. den Kontext
oben });
jQuery.extend() und jQuery.fn.extend()

Die Methoden jQuery.extend(object) und jQuery.fn.extend(object) werden verwendet, um zwei oder mehr Objekte zum ersten Objekt zusammenzuführen. Der relevante Quellcode lautet wie folgt (Teil):

Code kopieren Der Code lautet wie folgt:

jQuery.extend = jQuery.fn.extend = function() {
var-Optionen, Name, src, copy, copyIsArray, clone,//ein Satz lokaler Variablen definiert
target = arguments[0] ||. {},
i = 1,
length = arguments.length,
         deep = false;

jQuery.extend(object); Fügen Sie der jQuery-Klasse eine Klassenmethode hinzu, was als Hinzufügen einer statischen Methode verstanden werden kann. Zum Beispiel:

Code kopieren Der Code lautet wie folgt:

$.extend({
​add:function(a,b){returna b;}
});

Fügen Sie eine „statische Methode“ namens „add“ für jQuery hinzu, und dann können Sie diese Methode dort verwenden, wo jQuery eingeführt wird,

$.add(3,4); //return 7
jQuery.fn.extend(object), sehen Sie sich eine Codedemonstration auf der offiziellen Website wie folgt an:

Code kopieren Der Code lautet wie folgt:


<script><br> jQuery.fn.extend({<br>            check: function() {<br>                return this.each(function() {<br> This.checked = true;<br>             });<br> },<br> ​​​​ Deaktivieren Sie: function() {<br>               return this.each(function() {<br> This.checked = false;<br>             });<br> }<br> });<br> // Verwenden Sie die neu erstellte .check()-Methode<br> $( "input[type='checkbox']" ).check();<br> </script>

CSS-Auswahl-Engine Sizzle

Man kann sagen, dass jQuery für den Betrieb von DOM geboren wurde. Der Grund, warum jQuery so leistungsfähig ist, liegt an der CSS-Auswahl-Engine Sizzle. Die Parsing-Regeln zitieren ein Beispiel aus dem Internet:

selector:"div > p div.aaron input[type="checkbox"]"

Parsing-Regeln:
1 Folgen Sie von rechts nach links
2 Nehmen Sie das letzte Token heraus, z. B. [type="checkbox"]
                                                                                      Übereinstimmungen: Array[3]
Typ: „ATTR“
                                                                         Kontrollkästchen „]“
                                                                                              } 3 Filtertyp Wenn der Typ > ~ leer ist, einer der vier Beziehungsselektoren, dann überspringen und mit dem Filtern fortfahren
4, bis es mit ID, CLASS und TAG übereinstimmt, da es auf diese Weise über die Browserschnittstelle
abgerufen werden kann 5 Zu diesem Zeitpunkt hat die Samensammlung einen Wert, was die Bedingungen für die Pinselauswahl verringert
6. Wenn mehrere übereinstimmende Seed-Sammlungen vorhanden sind, ist eine weitere Filterung erforderlich. Ändern Sie den Selektor: „div > p div.aaron [type="checkbox"]“
7 OK, springe zur nächsten Stufe der Kompilierungsfunktion



aufgeschobenes Objekt

Bei der Entwicklung von Websites stoßen wir häufig auf bestimmte JavaScript-Vorgänge, die lange dauern. Darunter gibt es sowohl asynchrone Vorgänge (z. B. Ajax-Lesen von Serverdaten) als auch synchrone Vorgänge (z. B. das Durchlaufen eines großen Arrays), und die Ergebnisse sind nicht sofort verfügbar.

Der übliche Ansatz besteht darin, Rückruffunktionen für sie anzugeben. Das heißt, Sie legen vorab fest, welche Funktionen nach ihrer Ausführung aufgerufen werden sollen.

Allerdings ist jQuery sehr schwach, wenn es um Callback-Funktionen geht. Um dies zu ändern, hat das jQuery-Entwicklungsteam das verzögerte Objekt entworfen.

Einfach ausgedrückt ist das verzögerte Objekt die Callback-Funktionslösung von jQuery. Im Englischen bedeutet defer „Verzögerung“. Die Bedeutung eines verzögerten Objekts besteht also darin, die Ausführung bis zu einem bestimmten Punkt in der Zukunft zu „verzögern“.

Sehen Sie sich die traditionelle Schreibweise der Ajax-Operation von jQuery an:

Code kopieren Der Code lautet wie folgt: $.ajax({
URL: „test.html“,
Erfolg: function(){
alarm("Haha, erfolgreich!");
  },
error:function(){
alarm("Etwas ist schiefgelaufen!");
  }
});


Im obigen Code akzeptiert $.ajax() einen Objektparameter. Dieses Objekt enthält zwei Methoden: Die Erfolgsmethode gibt die Rückruffunktion an, nachdem die Operation erfolgreich war, und die Fehlermethode gibt die Rückruffunktion an, nachdem die Operation fehlgeschlagen ist.

Nach Abschluss der $.ajax()-Operation wird das XHR-Objekt zurückgegeben, wenn Sie eine Version von jQuery verwenden, die niedriger als 1.5.0 ist, und Sie können keine Kettenoperationen ausführen, wenn die Version höher als 1.5.0 ist , können die zurückgegebenen verzögerten Objekte verkettet werden.

Die neue Schreibweise lautet nun:

Code kopieren Der Code lautet wie folgt:

$.ajax("test.html")
​.done(function(){ alarm("Haha, erfolgreich!"); })
​.fail(function(){ alarm("Error!"); });

Geben Sie Rückruffunktionen für mehrere Vorgänge an

Ein weiterer großer Vorteil des verzögerten Objekts besteht darin, dass Sie eine Rückruffunktion für mehrere Ereignisse angeben können, was mit herkömmlichem Schreiben nicht möglich ist.

Bitte schauen Sie sich den folgenden Code an, der eine neue Methode $.when() verwendet:

Code kopieren Der Code lautet wie folgt:

$.when($.ajax("test1.html"), $.ajax("test2.html"))

 .done(function(){ alarm("Haha, erfolgreich!"); })

.fail(function(){ alarm("Fehler!"); });

Die Bedeutung dieses Codes besteht darin, zunächst zwei Operationen $.ajax("test1.html") und $.ajax("test2.html") auszuführen. Wenn beide erfolgreich sind, führen Sie den durch die Funktion done() angegebenen Rückruf aus ; wenn einer oder beide fehlschlagen, wird die durch fail() angegebene Callback-Funktion ausgeführt.

Implementierungsprinzip von jQuery.Deferred(func)

Intern werden drei Callback-Funktionslisten verwaltet: Erfolgs-Callback-Funktionsliste, Fehler-Callback-Funktionsliste und Nachrichten-Callback-Funktionsliste. Andere Methoden arbeiten und erkennen diese drei Listen.

Quellcodestruktur von jQuery.Deferred( func ):

Code kopieren Der Code lautet wie folgt:

jQuery.extend({

Zurückgestellt: Funktion( func ) {
// Erfolgreiche Rückruffunktionsliste
          var doneList = jQuery.Callbacks( "once Memory" ),
// Liste der Fehlerrückruffunktionen
              failList = jQuery.Callbacks( "once memory" ),
// Liste der Nachrichtenrückruffunktionen
           progressList = jQuery.Callbacks( "memory" ),
// Ausgangszustand
             state = „ausstehend“,
                       // Schreibgeschützte Kopie der asynchronen Warteschlange
               Versprechen = {
// erledigt, fehlgeschlagen, Fortschritt
                                  // state, isResolved, isRejected
                              // dann, immer
                            // Pipe
// versprechen             },
                                         // Asynchrone Warteschlange               deferred = Promise.Promise({}),
             Taste;
​​​​ // Methoden hinzufügen, um Erfolgs-, Fehler- und Nachrichtenrückruflisten auszulösen
for (Listen eingeben) {
              deferred[key] =LISTS[key].fire;
             deferred[ key "With" ] =LISTS[ key .fireWith;
}
                     // Eine Rückruffunktion hinzufügen, um den Status
festzulegen deferred.done( function() {
             state = "resolved";
}, failList.disable, progressList.lock )
         .fail( function() {
             state = „abgelehnt“;
            }, doneList.disable, progressList.lock );
                 // Wenn der Funktionsparameter func übergeben wird, wird er ausgeführt.
           if ( func ) {
                func.call(deferred, deferred);
}

// Rückgabe der asynchronen Warteschlange verzögert

         Rückgabe aufgeschoben;

},
}


jQuery.when(deferred)

Bietet die Möglichkeit, Rückruffunktionen basierend auf dem Status eines oder mehrerer Objekte auszuführen, typischerweise basierend auf einer asynchronen Warteschlange mit asynchronen Ereignissen.


Verwendung von jQuery.when(deferred)

Wenn mehrere asynchrone Warteschlangenobjekte übergeben werden, gibt die Methode jQuery.when() eine schreibgeschützte Kopie des neuen asynchronen Hauptwarteschlangenobjekts zurück. Die schreibgeschützte Kopie verfolgt den endgültigen Status der übergebenen asynchronen Warteschlange.

Sobald alle asynchronen Warteschlangen erfolgreich sind, wird die Erfolgsrückruffunktion der „Haupt“-Asynchronwarteschlange aufgerufen;

Wenn eine der asynchronen Warteschlangen ausfällt, wird die Fehlerrückruffunktion der asynchronen Hauptwarteschlange aufgerufen.

Code kopieren Der Code lautet wie folgt:

/*
Die Anfrage '/when.do?method=when1' gibt {"when":1}
zurück Die Anfrage '/when.do?method=when2' gibt {"when":2}
zurück Die Anfrage '/when.do?method=when3' gibt {"when":3}
zurück */
var whenDone = function(){ console.log( 'done', arguments ); },
WhenFail = function(){ console.log( 'fail', arguments ); };
$.when(
$.ajax( '/when.do?method=when1', { dataType: "json" } ),
$.ajax( '/when.do?method=when2', { dataType: "json" } ),
$.ajax( '/when.do?method=when3', { dataType: "json" } )
).done( whenDone ).fail( whenFail );

Bildbeschreibung

Asynchrone Warteschlange verzögert

Asynchrone Aufgaben und Rückruffunktionen entkoppeln

Stellen Sie Grundfunktionen für das Ajax-Modul, das Warteschlangenmodul und das Ready-Ereignis bereit.

Prototypeigenschaften und -methoden

Quellcode für Prototypeigenschaften und -methoden:

Code kopieren Der Code lautet wie folgt:

97 jQuery.fn = jQuery.prototype = {
98 Konstruktor: jQuery,
99 init: function(selector, context, rootjQuery) {}
210 Selektor: "",
213 jquery: „1.7.1“,
216 Länge: 0,
219 Größe: function() {},
223 toArray: function() {},
229 get: function( num ) {},
241 pushStack: function(elems, name, selector) {},
Jeweils 270: function( callback, args ) {},
274 bereit: function( fn ) {}, //
284 eq: function( i ) {},
291 zuerst: function() {},
295 zuletzt: function() {},
299 Slice: function() {},
304-Karte: Funktion( Rückruf ) {},
310 Ende: function() {},
316 push: push,
317 Sortierung: [].sort,
318 Spleiß: [].splice
319 };

Das Selektorattribut wird verwendet, um den Selektorausdruck aufzuzeichnen, wenn jQuery DOM-Elemente findet und filtert.
Das Attribut .length repräsentiert die Anzahl der Elemente im aktuellen JQuery-Objekt.
Die Methode .size() gibt die Anzahl der Elemente im aktuellen JQuery-Objekt zurück. Sie entspricht funktional der Eigenschaftslänge, aber die Länge sollte zuerst verwendet werden, da sie keinen Funktionsaufruf-Overhead verursacht.

Der Quellcode von

.size() lautet wie folgt:

Code kopieren Der Code lautet wie folgt:

size():function(){
Gibt this.length;
zurück }

Methode .toArray() konvertiert das aktuelle jQuery-Objekt in ein echtes Array. Das konvertierte Array enthält alle Elemente:

Code kopieren Der Code lautet wie folgt:

toArray: function() {
          return Slice.call( this );
},

Method.get(index) gibt das Element an der angegebenen Position im aktuellen jQuery-Objekt oder ein Array zurück, das alle Elemente enthält. Seine Quelle
Der Code lautet wie folgt:

Code kopieren Der Code lautet wie folgt:

Holen Sie sich: function(num) {
         return num == null ?

                      // Ein „sauberes“ Array zurückgeben
This.toArray():

// Nur das Objekt zurückgeben
( num < 0 ? this[ this.length num ] : this[ num ] );
},


Wenn keine Parameter übergeben werden, gibt der Aufruf von .toArray() ein Array zurück, das die gesperrten Elemente enthält. Wenn der Parameterindex angegeben ist, wird ein einzelnes Element zurückgegeben. Der Index beginnt mit der Zählung bei 0 und unterstützt negative Zahlen.

Zuerst wird beurteilt, ob num kleiner als 0 ist. Wenn es kleiner als 0 ist, wird der Index unter Verwendung der Länge num neu berechnet und dann wird der Array-Zugriffsoperator ([]) verwendet, um das Element zu erhalten Die angegebene Position ist eine kleine Methode, die negative Indizes unterstützt. Wenn sie größer oder gleich 0 ist, wird das Element direkt an der angegebenen Position zurückgegeben.

Detaillierte Erläuterung der Verwendung von eg() und get(): Zusammenfassung gängiger JQuery-Methoden und Anwendungsbeispiele

Methode .each() wird verwendet, um das aktuelle jQuery-Objekt zu durchlaufen und die Rückruffunktion für jedes Element auszuführen. Method.each() wird intern durch einfachen Aufruf der statischen Methode jQuery.each() implementiert:

Code kopieren Der Code lautet wie folgt:

every: function( callback, args ) {
          return jQuery.each( this, callback, args );
},

Die Rückruffunktion wird in dem Kontext ausgelöst, in dem das aktuelle Element der Kontext ist, dh das Schlüsselwort this zeigt immer auf das aktuelle Element, und die Rückgabe von false in der Rückruffunktion kann den Durchlauf beenden.

Methode .map() durchläuft das aktuelle jQuery-Objekt, führt die Rückruffunktion für jedes Element aus und fügt den Rückgabewert der Rückruffunktion in ein neues jQuery-Objekt ein. Diese Methode wird häufig verwendet, um den Wert einer Sammlung von DOM-Elementen abzurufen oder festzulegen.

Code kopieren Der Code lautet wie folgt:

map: function( callback ) {
          return this.pushStack( jQuery.map(this, function( elem, i ) {
                return callback.call(elem, i, elem);
         }));
},

Die Prototypmethode .pushStack() erstellt ein neues leeres jQuery-Objekt, fügt dann die Sammlung von DOM-Elementen in dieses jQuery-Objekt ein und behält einen Verweis auf das aktuelle jQuery-Objekt bei.

Der Prototyp method.pushStack() ist eine der Kernmethoden, die Unterstützung für die folgenden Methoden bietet:

jQuery-Objektdurchquerung: .eq(), .first(), .last(), .slice(), .map().

DOM-Suche und Filterung: .find(), .not(), .filter(), .closest(), .add(), .andSelf().

DOM-Durchquerung: .parent(), .parents(), .parentsUntil(), .next(), .prev(), .nextAll(), .prevAll(), .nextUnit(), .prevUnit() , .siblings(), .children(), .contents().

DOM-Einfügung: jQuery.before(), jQuery.after(), jQuery.replaceWith(), .append(), .prepent(), .before(), .after(), .replaceWith().
Definieren Sie die Methode .push(elems, name, selector), die 3 Parameter akzeptiert:

Parameterelemente: Array von Elementen (oder Array-ähnliches Objekt), das in das neue jQuery-Objekt eingefügt wird.

Parametername: Der Name der jQuery-Methode, die die Elemente des Elementarrays generiert.

Parameterauswahl: Der an die jQuery-Methode übergebene Parameter, der zum Ändern des Prototypattributs.selector verwendet wird.
Die Methode .end() beendet den letzten Filtervorgang in der aktuellen Kette und stellt die übereinstimmenden Elemente in ihrem vorherigen Zustand wieder her

Code kopieren Der Code lautet wie folgt:

Ende: function() {
         return this.prevObject || this.constructor(null);
},

Gibt das vorherige jQuery-Objekt zurück. Wenn das Attribut prevObect nicht vorhanden ist, wird ein leeres jQuery-Objekt erstellt und zurückgegeben. Die Methode .pushStack() dient zum Schieben in den Stapel und die Methode .end() zum Herausspringen aus dem Stapel

Statische Eigenschaften und Methoden

Der relevante Quellcode lautet wie folgt:

Code kopieren Der Code lautet wie folgt:

388 jQuery.extend({
 389     noConflict: function( deep ) {},
 402     isReady: false,
 406     readyWait: 1,
 409     holdReady: function( hold ) {},
 418     bereit: function( wait ) {},
 444     bindReady: function() {},
 492     isFunction: function( obj ) {},
 496     isArray: Array.isArray || Funktion( obj ) {},
 501     isWindow: function( obj ) {},
 505     isNumeric: function( obj ) {},
 509     Typ: Funktion( obj ) {},
 515     isPlainObject: function( obj ) {},
 544     isEmptyObject: function( obj ) {},
 551     Fehler: function( msg ) {},
 555     parseJSON: function( data ) {},
 581     parseXML: function( data ) {},
 601     noop: function() {},
 606     globalEval: function( data ) {},
 619     camelCase: function( string ) {},
 623     nodeName: function( elem, name ) {},
 628     jeweils: function( object, callback, args ) {},
 669     trimmen: trimmen ? function( text ) {} : function( text ) {},
 684     makeArray: function( array, results ) {},
 702     inArray: function( elem, array, i ) {},
 724     merge: function( first, second ) {},
 744     grep: function( elems, callback, inv ) {},
 761     map: function( elems, callback, arg ) {},
 794     Anleitung: 1,
 798     Proxy: function( fn, context ) {},
 825     Zugriff: Funktion( Elemente, Schlüssel, Wert, Exec, Fn, Pass) {},
 852     jetzt: function() {},
 858     uaMatch: function( ua ) {},
 870     sub: function() {},
 891     Browser: {}
 892 });
 

未完待续、、、今天就先到这里了,下次补齐。别急哈小伙伴们

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage