Angularjs'de derleme ve link fonksiyonu arasındaki fark nedir


208

Birisi basit terimlerle açıklayabilir mi?

Dokümanlar biraz geniş görünüyor. Birini diğerinin üzerinde ne zaman kullanacağımın özünü ve büyük resmini alamıyorum. İkisine zıt bir örnek harika olurdu.


2
Direktif fonksiyonlarına belki de daha kapsamlı bir genel bakış: Açısal direktifler - ne zaman derleme, kontrolör, ön bağlantı ve son bağlantı kullanılır .
Izhaki

Yanıtlar:


217
  • derleme işlevi - şablon DOM manipülasyonu için kullanın (yani, tElement = şablon elemanının manipülasyonu), dolayısıyla yönerge ile ilişkili şablonun tüm DOM klonlarına uygulanan manipülasyonlar.

  • link işlevi - DOM dinleyicilerini (örn., örnek kapsamındaki $ watch ifadeleri) ve örnek DOM manipülasyonunu (yani iElement = bireysel örnek öğesinin manipülasyonu) kaydetmek için kullanın.
    Şablon klonlandıktan sonra yürütülür. Örneğin, bir <ling-repeat ...> içinde, bağlantı işlevi o <li> öğesi için <li> şablonu (tElement) klonlandıktan (iElement'e) sonra yürütülür.
    $ Watch () yöntemi, yönerge örnek kapsamı özellik değişikliklerinden haberdar edilmesine izin verir (her bir örnekle ilişkilendirilmiş bir örnek kapsamı); bu da yönerge, içeriği içerik kapsamından kopyalayarak DOM'a güncellenmiş bir örnek değeri oluşturmaya izin verir DOM.

DOM dönüşümlerinin derleme işlevinde ve / veya bağlantı işlevinde yapılabileceğini unutmayın.

Çoğu direktif sadece bir link fonksiyonuna ihtiyaç duyar, çünkü çoğu direktif sadece belirli bir DOM elemanı örneği (ve örnek kapsamı) ile ilgilidir.

Hangisinin kullanılacağını belirlemenin bir yolu: derleme işlevinin scopebağımsız değişken almadığını düşünün . (Kasten kapsamı alan bir kapsamı alan transclude bağlama fonksiyonu argümanını görmezden geliyorum - bu nadiren kullanılır.) Derleme fonksiyonu (örnek) kapsamı gerektiren herhangi bir şey yapamaz - herhangi bir model / örnek kapsamı özelliğini izlemezseniz, örnek kapsamı bilgilerini kullanarak DOM'yi değiştiremezsiniz, örnek kapsamında tanımlanan işlevleri çağıramazsınız, vb.

Ancak, derleme işlevi (link işlevi gibi) özniteliklere erişebilir. DOM işlemleriniz örnek kapsamını gerektirmiyorsa, bir derleme işlevi kullanabilirsiniz. İşte bu nedenlerden ötürü yalnızca derleme işlevi kullanan bir yönerge örneği . Öznitelikleri inceler, ancak işini yapmak için bir örnek kapsamı gerektirmez.

Burada yalnızca derleme işlevi kullanan bir yönerge örneği verilmiştir. Direktifin yalnızca DOM şablonunu dönüştürmesi gerekir, böylece bir derleme işlevi kullanılabilir.

Hangisinin kullanılacağını belirlemenin başka bir yolu: link işlevinde "element" parametresini kullanmıyorsanız, muhtemelen bir link işlevine ihtiyacınız yoktur.

Çoğu direktifin bir bağlantı işlevi olduğundan, herhangi bir örnek vermeyeceğim - bulmak çok kolay olmalı.

Bir derleme işlevine ve bir bağlantı işlevine (veya bağlantı öncesi ve sonrası işlevlerine) ihtiyacınız varsa, 'derleme' özniteliği tanımlanmışsa 'link' özniteliği yoksayıldığından, derleme işlevinin link işlevlerini döndürmesi gerektiğini unutmayın.

Ayrıca bakınız


5
Derleme vs link hakkında en iyi açıklama.
Nexus23

1
Ne zaman if you don't use the "element" parameter in the link function, then you probably don't need a link function."element" yerine "kapsam" demek istediniz?
Jason Larke

69

Birkaç günlüğüne kafamı duvara dayayordum ve biraz daha açıklama yapıldığını hissediyorum.

Temel olarak dokümanlar, ayrımın büyük ölçüde bir performans artışı olduğunu belirtiyor. Derleme aşamasının, alt öğelerin kendileri derlenmeden ÖNCE DOM'yi değiştirmeniz gerektiğinde kullanıldığını yineleyeceğim.

Bizim amaçlarımız için, aksi takdirde kafa karıştırıcı olan terminolojiyi vurgulayacağım:

Derleyici SERVICE ($ compile), DOM'u işleyen ve direktiflerde çeşitli kod parçalarını çalıştıran açısal mekanizmadır.

FUNCTION derlemesi, direktif içinde belirli bir zamanda SERVICE ($ compile) derleyicisi tarafından çalıştırılan bir bit kodudur.

Derleme FUNCTION hakkında bazı notlar:

  1. ROOT öğesini (direktifinizin etkilediği bir öğeyi) değiştiremezsiniz, çünkü zaten DOM'un dış seviyesinden derlenmiştir (SERVICE derlemesi zaten bu öğedeki yönergeleri taramıştır).

  2. (İç içe) öğelere başka yönergeler eklemek isterseniz, şunlardan birini yapabilirsiniz:

    1. Derleme aşamasında bunları eklemeniz gerekir.

    2. Derleme hizmetini bağlantı aşamasına enjekte etmek ve öğeleri manuel olarak derlemek zorundasınız. AMA, iki kez bir şey derlemeye dikkat!

Ayrıca $ compile için iç içe ve açık çağrıların nasıl çalıştığını görmek de yararlıdır, bu yüzden http://jsbin.com/imUPAMoV/1/edit adresinde görüntülemek için bir oyun alanı oluşturdum . Temel olarak, sadece console.log adımlarını günlüğe kaydeder.

Bu kutuda gördüğünüz şeyin sonuçlarını burada anlatacağım. Tp ve sp özel yönergelerinin DOM'si için aşağıdaki gibi yuvalanmıştır:

<tp>
   <sp>
   </sp>
</tp>

Açısal derleme SERVICE:

tp compile
sp compile
tp pre-link
sp pre-link
sp post-link
tp post-link

Jsbin kodu ayrıca tp post-link FUNCTION açıkça sonunda derleme SERVICE çağırmak üçüncü yönerge (yukarı), sonunda her üç adımda yapar.

Şimdi, birinin çeşitli şeyler yapmak için derleme ve bağlantıyı nasıl kullanacağını göstermek için birkaç senaryodan geçmek istiyorum:

SENARYO 1: MAKRO Olarak Yönerge

Şablonunuzdaki bir özellikten türetebileceğiniz bir şeye dinamik olarak bir yönerge (ng-show diyelim) eklemek istiyorsunuz.

Şunu gösteren bir templateUrl'niz olduğunu varsayalım:

<div><span><input type="text"></span><div>

ve özel bir direktif istiyorsunuz:

<my-field model="state" name="address"></my-field>

DOM'u buna dönüştüren:

<div><span ng-show="state.visible.address"><input ng-model="state.fields.address" ...>

temel olarak, direktifinizin yorumlayabileceği tutarlı bir model yapısına sahip olan kazan plakasını azaltmak istersiniz. Başka bir deyişle: bir makro istiyorsunuz.

Bu, derleme aşaması için harika bir kullanımdır, çünkü tüm DOM manipülasyonlarını yalnızca niteliklerden bildiğiniz şeylere dayandırabilirsiniz. Öznitelikleri eklemek için jQuery kullanın:

compile: function(tele, tattr) {
   var span = jQuery(tele).find('span').first();
   span.attr('ng-show', tattr.model + ".visible." + tattr.name);
   ...
   return { 
     pre: function() { },
     post: function() {}
   };
}

İşlemlerin sırası şu şekildedir (bunu daha önce bahsedilen jsbin ile görebilirsiniz):

  1. SERVICE derlemesi alanımı bulur
  2. DOM'u güncelleyen yönerge üzerindeki FUNCTION derlemesini çağırır.
  3. Derleme SERVICE daha sonra elde edilen DOM ve COMPILES (özyinelemeli)
  4. SERVICE derlemesi daha sonra bağlantı öncesi yukarıdan aşağıya çağırır
  5. SERVICE derlemesi daha sonra bağlantı sonrası BOTTOM UP'ı çağırır, böylece alanımın bağlantı işlevi iç düğümler bağlandıktan SONRA çağrılır.

Yukarıdaki örnekte, direktifin tüm çalışmaları FUNCTION derlemesinde yapıldığından bağlantıya gerek yoktur.

Herhangi bir noktada, direktifteki kod SERVICE derleyicisinin ek elemanlar üzerinde çalışmasını isteyebilir.

Bu, derleme hizmetini enjekte ederseniz bir bağlantı işlevinde tam olarak aynı şeyi yapabileceğimiz anlamına gelir:

directive('d', function($compile) {
  return {
    // REMEMBER, link is called AFTER nested elements have been compiled and linked!
    link: function(scope, iele, iattr) {
      var span = jQuery(iele).find('span').first();
      span.attr('ng-show', iattr.model + ".visible." + iattr.name);
      // CAREFUL! If span had directives on it before
      // you will cause them to be processed again:
      $compile(span)(scope);
    }
});

$ Compile SERVICE ürününe ilettiğiniz öğelerin başlangıçta yönerge içermediğinden eminseniz (örneğin, tanımladığınız bir şablondan geldiler veya bunları açısal.element () ile oluşturdunuz), sonuçta hemen hemen önceki ile aynı (yine de bazı işleri tekrarlıyor olabilirsiniz). Ancak, öğenin üzerinde başka yönergeler varsa, bunların yeniden işlenmesine neden oldunuz, bu da her türlü düzensiz davranışa neden olabilir (örneğin, olayların ve saatlerin çift kaydı).

Bu nedenle, derleme aşaması makro tarzı işler için çok daha iyi bir seçimdir.

SENARYO 2: Kapsam verileri yoluyla DOM yapılandırması

Bu, yukarıdaki örnekten sonra gelir. DOM'yu işlerken kapsama erişmeniz gerektiğini varsayalım. Bu durumda, derleme bölümü sizin için işe yaramaz, çünkü bir kapsam mevcut olmadan önce olur.

Bu nedenle, doğrulamalarla bir girdiyi pezevenk etmek istediğinizi, ancak doğrulamalarınızı bir sunucu tarafı ORM sınıfından (DRY) dışa aktarmak ve bunların otomatik olarak uygulanmasını ve bu doğrulamalar için uygun istemci tarafı kullanıcı arayüzünü oluşturmasını istediğinizi varsayalım.

Modeliniz zorlayabilir:

scope.metadata = {
  validations: {
     address: [ {
       pattern: '^[0-9]',
       message: "Address must begin with a number"
     },
     { maxlength: 100,
       message: "Address too long"
     } ]
  }
};
scope.state = {
  address: '123 Fern Dr'
};

ve bir direktif isteyebilirsiniz:

<form name="theForm">
  <my-field model="state" metadata="metadata" name="address">
</form>

çeşitli doğrulama hatalarını göstermek için uygun yönergeleri ve div'leri otomatik olarak dahil etmek için:

<form name="theForm">
  <div>
    <input ng-model="state.address" type="text">
    <div ng-show="theForm.address.$error.pattern">Address must begin with a number</input>
...

Bu durumda, kapsama kesinlikle erişmeniz gerekir (doğrulamalarınızın depolandığı yer budur) ve eklemeleri manuel olarak derlemek zorunda kalacaksınız, yine bir şeyleri çift derlememeye dikkat edin. (bir yan not olarak, içeren form etiketinde bir ad ayarlamanız gerekir (burada Formun varsayıyorum) ve iElement.parent (). controller ('form') ile bağlantılı olarak erişebilirsiniz. $ name) .

Bu durumda derleme işlevi yazmanın bir anlamı yoktur. Bağlantı gerçekten istediğiniz şeydir. Adımlar şöyle olacaktır:

  1. Açısal yönergelerden tamamen yoksun bir şablon tanımlayın.
  2. Çeşitli nitelikleri ekleyen bir bağlantı işlevi tanımlayın
  3. Üst düzey öğenizde izin verebileceğiniz açısal yönergeleri (alanım yönergesi) KALDIRIN. Zaten işlenmişler ve bu, çift işlenmelerini önlemenin bir yoludur.
  4. Üst düzey öğenizde SERVICE derlemesini çağırarak bitirin

Şöyle ki:

angular.module('app', []).
directive('my-field', function($compile) {
  return {
    link: function(scope, iele, iattr) {
      // jquery additions via attr()
      // remove ng attr from top-level iele (to avoid duplicate processing)
      $compile(iele)(scope); // will pick up additions
    }
  };
});

Tabii ki, üst düzey öğeyi tekrar derlerken ng yönergelerinin yinelenen işlenmesi konusunda endişelenmekten kaçınmak için iç içe öğeleri tek tek derleyebilirsiniz.

Bu senaryoda son bir not: Bir sunucudan yapılan doğrulamaların tanımını zorlayacağınızı ima ettim ve örneğimde bunları zaten kapsamda veri olarak gösterdim. Ben bir REST API (ipucu: ertelenmiş derleme) bu veri çekme ihtiyacı ile başa çıkmak için nasıl anlamaya okuyucu için bir egzersiz olarak bırakın.

SCENARIO 3: bağlantı yoluyla iki yönlü veri bağlama

Elbette bağlantının en yaygın kullanımı, çift yönlü veri bağlamasını saat / uygula ile bağlamaktır. Çoğu direktif bu kategoriye girer, bu yüzden başka bir yerde yeterince kapsanmıştır.


2
Awsome & Cool Cevap!
Nexus23

İç içe öğeler çift derlenmeden nasıl eklenir?
Art713

50

Dokümanlardan:

Derleyici

Derleyici, DOM'ları öznitelikleri ararken gezen açısal bir hizmettir. Derleme işlemi iki aşamada gerçekleşir.

  1. Derleme: DOM'da gezinin ve tüm yönergeleri toplayın. Sonuç bir bağlama fonksiyonudur.

  2. Bağlantı: direktifleri bir kapsamla birleştirin ve canlı bir görüntü oluşturun. Kapsam modelindeki tüm değişiklikler görünüme yansıtılır ve görünümle olan kullanıcı etkileşimleri kapsam modeline yansıtılır. Kapsam modelini tek bir hakikat kaynağı yapmak.

Bazı direktifler ng-repeat , koleksiyondaki her öğe için DOM öğelerini bir kez klonlar. Bir derleme ve bağlantı aşamasına sahip olmak, klonlanmış şablonun yalnızca bir kez derlenmesi ve ardından her klon örneği için bir kez bağlanması gerektiğinden performansı artırır.

Dolayısıyla en azından bazı durumlarda, iki aşama bir optimizasyon olarak ayrı ayrı bulunur.


@ UmurKontacı'dan :

DOM dönüşümleri yapacaksanız, olması gerekir compile. Davranış değişikliği olan bazı özellikler eklemek isterseniz, içinde olmalıdır link.


46
Eğer DOMdönüşüm yapacaksanız , compilebazı özellikler eklemek istiyorsanız davranış değişiklikleri, olması gerekir olmalıdır link.
Umur Kontacı

4
+1 ila yukarıdaki yorum; bu şimdiye kadar bulduğum en kısa açıklama. Ben buldum öğretici ile eşleşir burada .
Benny Bottema

18

Bu Misko'nun direktifler konusundaki konuşmasından. http://youtu.be/WqmeI5fZcho?t=16m23s

Derleyici işlevini bir şablon üzerinde çalışan ve örneğin bir sınıf veya buna benzer bir sınıf ekleyerek şablonun kendisini değiştirmesine izin verilen şey olarak düşünün. Ancak, bağlama işlevinin kapsama erişimi olduğundan ve belirli bir şablonun her örneği için bir kez yürütülen bağlantı işlevidir. Derleme işlevlerinin içine yerleştirebileceğiniz tek şey, tüm örneklerde ortak olan şeylerdir.


10

İpliğe biraz geç. Ancak, gelecekteki okuyucuların yararına:

Angular JS'de Derleme ve Bağlantı'yı çok güzel bir şekilde açıklayan şu videoyla karşılaştım:

https://www.youtube.com/watch?v=bjFqSyddCeA

Buradaki tüm içeriği kopyalamak / yazmak hoş olmaz. Derleme ve Bağlantı aşamalarının her aşamasını açıklayan videodan birkaç ekran görüntüsü aldım:

Açısal JS'de Derleme ve Bağlantı

Açısal JS'de Derleme ve Bağlantı - İç İçe Direktifler

İkinci ekran görüntüsü biraz kafa karıştırıcı. Ancak, adım numaralandırmasını takip edersek, oldukça basittir.

İlk döngü: "Derleme" önce tüm yönergelerde gerçekleştirilir.
İkinci döngü: "Kontrolör" ve "Ön Bağlantı" gerçekleştirilir (birbiri ardına sadece) Üçüncü döngü: "Bağlantı Sonrası" ters sırada gerçekleştirilir (en içten başlayarak)

Yukarıdakileri gösteren kod aşağıdadır:

var app = angular.module ('app', []);

app.controller ('msg', ['$ scope', işlev ($ scope) {

}]);

app.directive ('mesaj', işlev ($ interpolate) {
    dönüş{

        compile: function (tElement, tAttributes) { 
            console.log (tAttributes.text + "-In compile ..");
            dönüş {

                pre: function (kapsam, iElement, iAttributes, denetleyici) {
                    console.log (iAttributes.text + "-In pre ..");
                },

                post: function (kapsam, iElement, iAttributes, denetleyici) {
                    console.log (iAttributes.text + "-In Post ..");
                }

            }
        },

        denetleyici: işlev ($ scope, $ element, $ attrs) {
            console.log ($ attrs.text + "-In denetleyici ..");
        },

    }
});
<body ng-app="app">
<div ng-controller="msg">
    <div message text="first">
        <div message text="..second">
            <div message text="....third">

            </div>              
        </div>  
    </div>
</div>

GÜNCELLEME:

Aynı videonun 2. Bölümüne buradan ulaşabilirsiniz: https://www.youtube.com/watch?v=1M3LZ1cu7rw Videoda, Angular JS'nin Derleme ve Bağlantı işlemi sırasında DOM ve olayları nasıl değiştireceğiniz hakkında daha fazla bilgi açıklanmaktadır .


Bir DOM kodunu , bir satıcı direktifinden kısmen değiştirilmeden önce compileve postdeğiştirmek için kullanılır template.
jedi

6

İki Aşama: Derleme ve Bağlantı

Derleme:

Direktifleri (elemanlar / nitelikler / sınıflar / yorumlar) aramak için DOM ağacında gezinin. Bir direktifin her derlenmesi şablonunu değiştirebilir veya henüz derlenmemiş içeriğini değiştirebilir. Bir yönerge eşleştiğinde, daha sonraki bir aşamada öğeleri birbirine bağlamak için kullanılan bir bağlama işlevi döndürür. Derleme aşamasının sonunda, derlenmiş yönergelerin ve ilgili bağlantı işlevlerinin bir listesine sahibiz.

Bağlantı:

Bir öğe bağlandığında, DOM ağacı DOM ağacındaki dallanma noktasında kırılır ve içeriklerin yerini şablonun derlenmiş (ve bağlantılı) örneği alır. Yerinden edilen orijinal içerik ya atılır ya da ekleme durumunda şablona yeniden bağlanır. Transküsyon ile, iki parça birbirine bağlanır (bir parça zincir gibi, şablon parçası ortadadır). Link işlevi çağrıldığında, şablon zaten bir kapsama bağlanmış ve öğenin alt öğesi olarak eklenmiştir. Bağlantı işlevi, DOM'u daha fazla manipüle etme ve değişiklik dinleyicilerini ayarlama fırsatınızdır.


3

Bu soru eski, yardımcı olabilecek kısa bir özet yapmak istiyorum:

  • Derleme tüm yönerge örneği için bir kez çağrıldı
  • Derleme ana amacı, bağlantı (ve muhtemelen öncesi / sonrası) işlevini / nesnesini döndürmek / oluşturmaktır. Ayrıca direktifin örnekleri arasında paylaşılan şeyleri de başlatabilirsiniz.
  • Bence "link" bu özellik için kafa karıştırıcı bir isim. "Ön renderleme" yi tercih ederim.
  • link her yönerge örneği için çağrılır ve amacı yönerge DOM'da oluşturulmasını hazırlamaktır.

1
öneri adı için bir artı: "ön render"
Hailong Cao
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.