Açısal yönergeler - derleme, denetleyici, ön bağlantı ve bağlantı sonrası ne zaman ve nasıl kullanılır [kapalı]


451

Bir Açısal yönerge yazarken, yönerge bildirildiği öğenin DOM davranışını, içeriğini ve görünümünü değiştirmek için aşağıdaki işlevlerden herhangi biri kullanılabilir:

  • derleme
  • kontrolör
  • Ön bağlantı
  • Post-bağlantı

Hangi fonksiyonun kullanılması gerektiğine dair bir karışıklık var gibi görünüyor. Bu soru şunları kapsamaktadır:

Direktifle ilgili temel bilgiler

İşlev doğa, yapılacaklar ve yapılmayacaklar

İlgili sorular:


27
Ne ne ?
haimlit

2
@Ian Bkz: Operatöre aşırı yükleme . Temelde bu topluluk wiki'si için tasarlanmıştır. İlgili soruların cevaplarının çoğu, tam resmi vermeyecek şekilde kısmi.
Izhaki

8
Bu harika bir içerik, ancak burada her şeyin Soru-Cevap biçiminde tutulmasını istiyoruz. Belki de bunu birden fazla ayrı soruya bölmek ve daha sonra onlara wiki etiketinden bağlantı vermek istersiniz?
Flekso

57
Bu yazı konu dışı ve blog biçiminde olsa da, Açısal direktiflerin derinlemesine bir açıklamasını sağlamada en yararlıydı. Lütfen bu yayını silmeyin, yöneticiler!
Exegesis

12
Dürüst olmak gerekirse, orijinal dokümanlarla bile uğraşmıyorum. Bir yığın aktarımı gönderisi veya bir blog genellikle saniyeler içinde gitmemi sağlıyor, orijinal dokümanları anlamaya çalışırken saçlarımı 15-30 dakika yırtarak.
David

Yanıtlar:


168

Yönerge işlevleri hangi sırada yürütülür?

Tek bir yönerge için

Aşağıdaki paketten yola çıkarak aşağıdaki HTML işaretlemesini göz önünde bulundurun:

<body>
    <div log='some-div'></div>
</body>

Aşağıdaki direktif beyanı ile:

myApp.directive('log', function() {

    return {
        controller: function( $scope, $element, $attrs, $transclude ) {
            console.log( $attrs.log + ' (controller)' );
        },
        compile: function compile( tElement, tAttributes ) {
            console.log( tAttributes.log + ' (compile)'  );
            return {
                pre: function preLink( scope, element, attributes ) {
                    console.log( attributes.log + ' (pre-link)'  );
                },
                post: function postLink( scope, element, attributes ) {
                    console.log( attributes.log + ' (post-link)'  );
                }
            };
         }
     };  

});

Konsol çıkışı:

some-div (compile)
some-div (controller)
some-div (pre-link)
some-div (post-link)

Bunun compileilk önce, sonra controller, sonra da pre-linkson olarak yürütüldüğünü görebiliriz post-link.

Yuvalanmış yönergeler için

Not: Aşağıdaki, çocuklarını bağlantı işlevlerinde görüntüleyen yönergeler için geçerli değildir. Oldukça az Açısal yönerge bunu yapar (ngIf, ngRepeat veya ile herhangi bir yönerge gibi transclude). Bu yönergeler, alt yönergeleri linkçağrılmadan önce yerel olarak işlevlerini çağırır compile.

Orijinal HTML işaretlemesi genellikle her biri kendi yönergesine sahip iç içe öğelerden oluşur. Aşağıdaki işaretlemede olduğu gibi ( plunk'a bakın ):

<body>
    <div log='parent'>
        <div log='..first-child'></div>
        <div log='..second-child'></div>
    </div>
</body>

Konsol çıkışı şu şekilde görünecektir:

// The compile phase
parent (compile)
..first-child (compile)
..second-child (compile)

// The link phase   
parent (controller)
parent (pre-link)
..first-child (controller)
..first-child (pre-link)
..first-child (post-link)
..second-child (controller)
..second-child (pre-link)
..second-child (post-link)
parent (post-link)

Burada iki aşamayı ayırt edebiliriz - derleme aşaması ve bağlantı aşaması.

Derleme aşaması

DOM yüklendiğinde Açısal, derleme aşamasını başlatır, burada işaretleme yukarıdan aşağıya geçer ve compiletüm yönergeleri çağırır . Grafiksel olarak şöyle ifade edebiliriz:

Çocuklar için derleme döngüsünü gösteren bir resim

Bu aşamada, derleme işlevinin aldığı şablonların kaynak şablonlar (örnek şablon değil) olduğunu belirtmek belki de önemlidir.

Bağlantı aşaması

DOM örnekleri genellikle basitçe DOM'ye oluşturulan bir kaynak şablonunun sonucudur, ancak bunlar tarafından oluşturulabilir ng-repeatveya anında tanıtılabilir.

DOM'ye yönerge içeren bir öğenin yeni bir örneği oluşturulduğunda, bağlantı aşaması başlar.

Bu aşamada, Açısal çağrıları controller, pre-linkçocukları yineler ve aşağıdaki post-linkgibi tüm direktifleri çağırır :

Bağlantı aşaması adımlarını gösteren bir resim


5
@lzhaki Akış çizelgesi hoş görünüyor. Grafik aracının adını paylaşmak ister misiniz? :)
merlin

1
@merlin OmniGraffle kullandım (ancak illustrator veya inkscape kullanmış olabilirim - hız dışında, OmniGraffle'ın bu çizim söz konusu olduğunda diğer grafik araçlarından daha iyi yaptığı hiçbir şey yoktur).
Izhaki

2
@ Anant'ın düşmanı kayboldu, bu yüzden yeni bir tane daha: plnkr.co/edit/kZZks8HN0iFIY8ZaKJkA?p=preview Günlük ifadelerini görmek için JS konsolunu açın

Ng-repeat çocuk yönergeleri için kullanıldığında neden bu doğru değil ??? Gösteriye
Luckylooke

Sizin gümlemek ng-tekrarı altında yönergesi ile çocukları var @Luckylooke (yani ne tekrarlanan varlık bir yönergesi ile bir şablon it would varsa, onların derleme sadece ng-tekrarlama linke sonra çağrılmasını görürdük..
Izhaki

90

Bu işlev çağrıları arasında başka neler olur?

Çeşitli direktifi işlevleri iki adlandırılan diğer açısal fonksiyonları içinden yürütülür $compile(yönerge en compileyürütülür) ve adlandırılan dahili fonksiyonu nodeLinkFn(yönerge en controller, preLinkve postLinkyürütülür). Direktif fonksiyonlar çağrılmadan önce ve sonra açısal fonksiyon içinde çeşitli şeyler meydana gelir. Belki de en önemlisi çocuk özyineleme. Aşağıdaki basitleştirilmiş çizim, derleme ve bağlantı aşamalarındaki önemli adımları göstermektedir:

Açısal derleme ve bağlantı aşamalarını gösteren bir resim

Bu adımları göstermek için aşağıdaki HTML işaretlemesini kullanalım:

<div ng-repeat="i in [0,1,2]">
    <my-element>
        <div>Inner content</div>
    </my-element>
</div>

Aşağıdaki yönergeyle:

myApp.directive( 'myElement', function() {
    return {
        restrict:   'EA',
        transclude: true,
        template:   '<div>{{label}}<div ng-transclude></div></div>'
    }
});

derleme

compileAPI görünüyor böylece gibi:

compile: function compile( tElement, tAttributes ) { ... }

Genellikle, töğelerin ve sağlanan özniteliklerin örnek yerine kaynak şablondakiler olduğunu belirtmek için parametrelerin önüne eklenir .

compileAktarılan içeriğe yapılan çağrıdan önce (varsa) kaldırılır ve şablon işaretlemeye uygulanır. Böylece, compileişleve sağlanan eleman şöyle görünecektir:

<my-element>
    <div>
        "{{label}}"
        <div ng-transclude></div>
    </div>
</my-element>

Aktarılan içeriğin bu noktada yeniden eklenmediğine dikkat edin.

Direktifin çağrısının ardından .compileAngular, direktif tarafından henüz getirilmiş olanlar da dahil olmak üzere tüm alt öğeleri (örneğin şablon öğeleri) geçecektir.

Örnek oluşturma

Bizim durumumuzda, yukarıdaki kaynak şablonun üç örneği (tarafından ng-repeat) oluşturulacaktır . Bu nedenle, aşağıdaki dizi, örnek başına bir kez üç kez yürütülür.

kontrolör

controllerAPI içerir:

controller: function( $scope, $element, $attrs, $transclude ) { ... }

Bağlantı aşamasına girildiğinde, döndürülen bağlantı işlevi $compileartık bir kapsamla sağlanır.

İlk olarak, link işlevi istenirse bir alt kapsam ( scope: true) veya yalıtılmış bir kapsam ( scope: {...}) oluşturur.

Daha sonra kontrolör yürütülür, örnek öğesinin kapsamı sağlanır.

Ön bağlantı

pre-linkAPI görünüyor böylece gibi:

function preLink( scope, element, attributes, controller ) { ... }

Neredeyse hiçbir şey yönergesi en çağrısına arasında olur .controllerve .preLinkişlevi. Açısal yine de her birinin nasıl kullanılması gerektiğine dair önerilerde bulunur.

.preLinkÇağrının ardından, link işlevi her bir alt öğeyi geçecektir - doğru bağlantı işlevini çağırarak ve ona geçerli kapsamı ekler (alt öğeler için ana kapsam görevi görür).

Sonrası bağlantı

post-linkAPI benzer olduğu pre-linkişlevin:

function postLink( scope, element, attributes, controller ) { ... }

Bir direktifin .postLinkişlevi çağrıldığında, tüm çocukların .postLinkişlevleri de dahil olmak üzere tüm alt öğelerinin bağlantı sürecinin tamamlandığını fark etmekte fayda var .

Bu .postLink, çağrıldığında, çocukların 'canlı' olduğu hazırdır. Bu içerir:

  • bağlanma verileri
  • ekleme uygulandı
  • kapsam ekli

Bu aşamadaki şablon böylece şöyle görünecektir:

<my-element>
    <div class="ng-binding">
        "{{label}}"
        <div ng-transclude>                
            <div class="ng-scope">Inner content</div>
        </div>
    </div>
</my-element>

3
Bu çizimi nasıl oluşturdunuz?
Royi Namir

6
@RoyiNamir Omnigraffle.
Izhaki

43

Çeşitli işlevler nasıl bildirilir?

Derleme, Denetleyici, Ön Bağlantı ve Son Bağlantı

Biri dört işlevin tümünü kullanacaksa, yönerge şu formu izler:

myApp.directive( 'myDirective', function () {
    return {
        restrict: 'EA',
        controller: function( $scope, $element, $attrs, $transclude ) {
            // Controller code goes here.
        },
        compile: function compile( tElement, tAttributes, transcludeFn ) {
            // Compile code goes here.
            return {
                pre: function preLink( scope, element, attributes, controller, transcludeFn ) {
                    // Pre-link code goes here
                },
                post: function postLink( scope, element, attributes, controller, transcludeFn ) {
                    // Post-link code goes here
                }
            };
        }
    };  
});

Derlemenin hem ön bağlantı hem de bağlantı sonrası işlevlerini içeren bir nesne döndürdüğüne dikkat edin; Açısal lingo'da derleme işlevinin bir şablon işlevi döndürdüğünü söylüyoruz .

Derleme, Denetleyici ve Bağlantı Sonrası

Eğer pre-linkgerekli değildir, derleme işlevi basitçe yerine bir tanım nesnenin sonrası bağlantı işlev döndürecek şöyle olabilir:

myApp.directive( 'myDirective', function () {
    return {
        restrict: 'EA',
        controller: function( $scope, $element, $attrs, $transclude ) {
            // Controller code goes here.
        },
        compile: function compile( tElement, tAttributes, transcludeFn ) {
            // Compile code goes here.
            return function postLink( scope, element, attributes, controller, transcludeFn ) {
                    // Post-link code goes here                 
            };
        }
    };  
});

Bazen, compile(post) linkyöntemi tanımlandıktan sonra bir yöntem eklemek ister . Bunun için aşağıdakiler kullanılabilir:

myApp.directive( 'myDirective', function () {
    return {
        restrict: 'EA',
        controller: function( $scope, $element, $attrs, $transclude ) {
            // Controller code goes here.
        },
        compile: function compile( tElement, tAttributes, transcludeFn ) {
            // Compile code goes here.

            return this.link;
        },
        link: function( scope, element, attributes, controller, transcludeFn ) {
            // Post-link code goes here
        }

    };  
});

Denetleyici ve Bağlantı Sonrası

Derleme işlevi gerekmiyorsa, bildirimi tamamen atlayabilir ve linkyönerge yapılandırma nesnesinin özelliği altında bağlantı sonrası işlevi sağlayabilir :

myApp.directive( 'myDirective', function () {
    return {
        restrict: 'EA',
        controller: function( $scope, $element, $attrs, $transclude ) {
            // Controller code goes here.
        },
        link: function postLink( scope, element, attributes, controller, transcludeFn ) {
                // Post-link code goes here                 
        },          
    };  
});

Denetleyici yok

Yukarıdaki örneklerin herhangi birinde, controllergerekirse işlev kaldırılabilir . Örneğin, yalnızca post-linkişlev gerekiyorsa aşağıdakiler kullanılabilir:

myApp.directive( 'myDirective', function () {
    return {
        restrict: 'EA',
        link: function postLink( scope, element, attributes, controller, transcludeFn ) {
                // Post-link code goes here                 
        },          
    };  
});

31

Kaynak şablon ile örnek şablon arasındaki fark nedir ?

Angular'ın DOM manipülasyonuna izin vermesi, derleme sürecine giriş işaretlemesinin bazen çıktıdan farklı olduğu anlamına gelir. Özellikle, bazı girdi işaretlemeleri ng-repeatDOM'ye verilmeden önce birkaç kez (gibi ) klonlanabilir .

Açısal terminoloji biraz tutarsızdır, ancak yine de iki tür işaretleme arasında ayrım yapar:

  • Kaynak şablonu - gerekirse klonlanacak işaretleme. Klonlanırsa, bu işaretleme DOM'ye verilmez.
  • Örnek şablonu - DOM'a dönüştürülecek gerçek işaretleme. Klonlama söz konusuysa, her örnek bir klon olacaktır.

Aşağıdaki biçimlendirme bunu göstermektedir:

<div ng-repeat="i in [0,1,2]">
    <my-directive>{{i}}</my-directive>
</div>

Kaynak html,

    <my-directive>{{i}}</my-directive>

kaynak şablon görevi görür.

Ancak bir ng-repeatdirektifin içine sarıldığından , bu kaynak şablonu klonlanacaktır (bizim durumumuzda 3 kez). Bu klonlar örnek şablonudur, her biri DOM'de görünür ve ilgili kapsama bağlanır.


23

Derleme işlevi

Her direktifin compileişlevi, Açısal önyükleme yapıldığında yalnızca bir kez çağrılır.

Resmi olarak, bu, kapsam veya veri bağlama içermeyen (kaynak) şablon manipülasyonlarının gerçekleştirileceği yerdir.

Öncelikle, bu optimizasyon amacıyla yapılır; aşağıdaki işaretlemeyi düşünün:

<tr ng-repeat="raw in raws">
    <my-raw></my-raw>
</tr>

<my-raw>Yönerge DOM biçimlendirme özel bir set verecek. Böylece:

  • ng-repeatKaynak şablonun ( <my-raw>) çoğaltılmasına izin verin ve ardından her örnek şablonunun işaretlemesini değiştirin ( compileişlevin dışında ).
  • Kaynak şablonu, istenen işaretlemeyi ( compileişlevde) içerecek şekilde değiştirin ve ardından ng-repeatçoğaltmaya izin verin .

rawsKoleksiyonda 1000 öğe varsa , ikinci seçenek öncekinden daha hızlı olabilir.

Yapmak:

  • İşaretlemeyi örneklere (klonlara) şablon olarak hizmet edecek şekilde değiştirin.

Yapma

  • Olay işleyicileri ekleyin.
  • Alt öğeleri inceleyin.
  • Özelliklerle ilgili gözlemler oluşturun.
  • Kapsamda saatler ayarlayın.

20

Denetleyici işlevi

Her bir direktifin controllerişlevi, yeni bir ilgili öğe başlatıldığında çağrılır.

Resmi olarak, controllerfonksiyon burada:

  • Denetleyiciler arasında paylaşılabilecek denetleyici mantığını (yöntemleri) tanımlar.
  • Kapsam değişkenlerini başlatır.

Yine, yönerge izole bir kapsam içeriyorsa, ana kapsamdan miras alan herhangi bir mülkün henüz mevcut olmadığını hatırlamak önemlidir.

Yapmak:

  • Denetleyici mantığını tanımlama
  • Kapsam değişkenlerini başlatma

Yapma:

  • Alt öğeleri inceleyin (henüz oluşturulmamış, kapsama bağlı, vb.).

Controller içinde direktiften bahsettiğinize sevindim, kapsamı başlatmak için harika bir yer. Bunu keşfetmekte zorlandım.
jsbisht

1
Denetleyici "Kapsamı başlat" DEĞİLDİR, yalnızca kendisinden bağımsız olarak başlatılmış olan kapsama erişir.
Dmitri Zaitsev

@DmitriZaitsev detaylara iyi dikkat. Metni değiştirdim.
Izhaki

19

Bağlantı sonrası işlevi

Ne zaman post-linkbağlayıcı, ekleme, vb - fonksiyon denir, önceki tüm adımların yer almış

Bu, genellikle oluşturulan DOM'u daha fazla manipüle etmek için bir yerdir.

Yapmak:

  • DOM (oluşturulmuş ve böylece somutlaştırılmış) öğeleri işleyin.
  • Olay işleyicileri ekleyin.
  • Alt öğeleri inceleyin.
  • Özelliklerle ilgili gözlemler oluşturun.
  • Kapsamda saatler ayarlayın.

9
Herhangi birinin bağlantı işlevini kullanması durumunda (bağlantı öncesi veya bağlantı sonrası olmadan), bağlantı sonrası ile eşdeğer olduğunu bilmek iyidir.
Asaf David

15

Ön bağlantı işlevi

Her bir direktifin pre-linkişlevi, yeni bir ilgili öğe başlatıldığında çağrılır.

Daha önce derleme sırası bölümünde görüldüğü gibi, pre-linkfonksiyonlara parent-then-child, post-linkfonksiyonlara da çağrılır child-then-parent.

pre-linkFonksiyon nadiren kullanılır, ancak özel senaryolarda yararlı olabilir; örneğin, bir çocuk denetleyici ana denetleyiciye kendini kaydettirdiğinde, ancak kayıt bir parent-then-childşekilde olmalıdır ( ngModelControllerişleri bu şekilde yapar).

Yapma:

  • Alt öğeleri inceleyin (henüz oluşturulmamış, kapsama bağlı, vb.).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.